您的位置:首页 > 编程语言 > Java开发

java学习【知识点及代码16】

2017-05-22 21:22 369 查看
一:线程中的一些方法(线程中存在的现象)

1.1 线程加入
public final void join()
等待该线程中止,其他线程才能继续抢着执行


package day16.edu_01;
public class Test {
public static void main(String[] args) {
//创建3个线程
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();

//给线程起名字
t1.setName("小白");
t2.setName("小黑");
t3.setName("小红");

//开启线程
t1.start();

//线程加入
try {
t1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t2.start();
t3.start();
}
}


package day16.edu_01;

public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+"  "+i);
}
}
}


1.2 线程礼让
public static void yield():暂停当前正在执行的线程对象,并执行其他线程。
作用:让线程间的执行更和谐一些,但是实际上做不到。可以通过后面讲解的知识来实现。


package day16.edu_02;
public class Test {
public static void main(String[] args) {
//创建2个线程
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();

//给线程设置名字
t1.setName("小白");
t2.setName("小黑");

//开启线程
t1.start();
t2.start();
}
}


package day16.edu_02;

public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+"  "+i);
//实现线程礼让
MyThread.yield();
}
}
}


1.3 线程死亡
public final void stop():直接杀死
public void interrupt():直接杀死,在死前,还可以有遗言。


package day16.edu_03;

import java.text.SimpleDateFormat;
import java.util.Date;

public class MyThread extends Thread{
@Override
public void run() {
//打印开始的时间
System.out.println("开始时间:"+new SimpleDateFormat("HH:mm:ss").format(new Date()));

//休眠10秒
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
System.out.println("我被杀死了");
}
System.out.println("结束时间:"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}


package day16.edu_03;

public class Test {
public static void main(String[] args) {
//创建线程对象
MyThread t = new MyThread();
//开启线程
t.start();

try {
Thread.sleep(3000);

//public final void stop():直接杀死
t.stop();

//public void interrupt():直接杀死,在死前,还可以有遗言。
//t.interrupt();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();

}
}
}


1.4 线程休眠
static void sleep(long millis) 线程睡一会


二:线程的生命周期(画图讲解),面试题

1.新建
2.就绪
3.运行
4.有可能阻塞
5.死亡




三:线程间通信(生产消费者问题):不同类型线程针对同一个资源的操作

画图讲解:1.系统不仅要卖票还要入票

2.不仅要卖肉夹馍还要生产肉夹馍

四:案例:以给学生设置和获取姓名和年龄为例,演示线程通信问题

线程间通讯:

资源:Student

设置数据线程:SetThread

获取数据线程:GetThread

测试类:StudentDemo

问题1:控制台出现的结果是:null—0

设置和获取线程使用的学生资源不是同一个。
如何解决这个问题呢?
把资源作为构造参数传递即可。


问题2:产生了2个问题

A:相同的数据出现了多次
CPU的一点点时间片就足够我们的程序执行很多次
B:数据出现了问题(数据安全问题)
a:是否是多线程环境
是
b:是否有共享数据
1296d
是
c:是否有多条语句操作共享数据
是
既然我们知道它是出现了数据安全问题,我们就应该来解决它。
如何解决呢?加锁


问题3:加了锁以后,数据还是有问题

A:多个线程都要加锁
B:多个线程加的锁必须是同一把锁


package day16.edu_04;

public class Student {
String name;
int age;
}


package day16.edu_04;

public class SetThread implements Runnable{
//Student s = new Student();
private Student s;
private int x=0;

public SetThread(Student s){
this.s = s;
}

@Override
public void run() {
while (true) {
synchronized (s) {
if (x%2==0) {
s.name="小白";
s.age=12;
}else{
s.name="小黑";
s.age=13;
}
x++;
}

}

}
}


package day16.edu_04;

public class GetThread implements Runnable{
//Student s = new Student();
private Student s;

public GetThread(Student s){
this.s = s;
}
@Override
public void run() {
while (true) {
synchronized (s) {
System.out.println(s.name+"  "+s.age);
}
}
}
}


package day16.edu_04;

public class Test {
public static void main(String[] args) {
//创建一个学生对象
Student s = new Student();

//创建设置和获取线程,并开启线程
SetThread st = new SetThread(s);
GetThread gt = new GetThread(s);

Thread t1 = new Thread(st);
Thread t2 = new Thread(gt);

//开启线程
t1.start();
t2.start();
}
}


五:将上述代码使用等待唤醒机制改进,实现礼让效果

package day16.edu_05;

public class Student {
String name;
int age;
boolean flag;
}


package day16.edu_05;

public class SetThread implements Runnable{
private Student s;
private int x=0;

public SetThread(Student s){
this.s = s;
}

@Override
public void run() {
while (true) {
synchronized (s) {
if (s.flag) {
//等待
try {
s.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
if (x%2==0) {
s.name="小白";
s.age=12;
}else{
s.name="小黑";
s.age=13;
}
x++;
//此时对象有数据了
s.flag=true;
s.notify();
}
}
}
}
}


package day16.edu_05;

public class GetThread implements Runnable{
private Student s;

public GetThread(Student s){
this.s = s;
}

@Override
public void run() {
while (true) {
synchronized (s) {
if(!s.flag){
//等待设置线程给对象设置数据
try {
s.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}else{

System.out.println(s.name+"  "+s.age);
//当获取线程从学生对象中获取了数据之后,我们就默认他已经没有数据了,此时我们应该
//继续让设置线程继续给学生对象设置信息
s.flag=false;
s.notify();
}
}
}
}
}


package day16.edu_05;

public class StudentDemo {
public static void main(String[] args) {
//创建学生对象
Student s = new Student();
//创建学生对象
SetThread st = new SetThread(s);
GetThread gt = new GetThread(s);
Thread t1 = new Thread(st);
Thread t2 = new Thread(gt);

//开启线程
t1.start();
t2.start();
}
}


六:将上述代码继续优化

1.私有化Student类的成员变量

2.在类的内部提供设置和获取的同步方法

package day16.edu_06;

public class Student {
private String name;
private int age;
private boolean flag;

//提供公共的方法设置信息
public synchronized void setInfo(String name,int age){
if(this.flag){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//没有值的话,在这里给对象设置数据
this.name=name;
this.age=age;

//更改标记,唤醒获取线程获取数据
this.flag=true;
this.notify();

}
public synchronized void getInfo(){
if(!this.flag){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
//有数据,取数据
System.out.println(this.name+"  "+this.age);
//取完数据之后,就没有数据了
this.flag=false;
this.notify();
}

}
}


package day16.edu_06;

public class SetThread implements Runnable{
private Student s;
private int x=0;

public SetThread(Student s){
this.s = s;
}

@Override
public void run() {
while (true) {
if (x%2==0) {
s.setInfo("小白", 13);
} else {
s.setInfo("小黑", 14);
}

x++;
}
}
}


package day16.edu_06;

public class GetThread implements Runnable{
private Student s;

public GetThread(Student s){
this.s = s;
}

@Override
public void run() {
while(true){
s.getInfo();
}

}
}


package day16.edu_06;

public class StudentDemo {
public static void main(String[] args) {
//创建学生对象
Student s = new Student();
//创建设置线程和获取线程
SetThread st = new SetThread(s);
GetThread gt = new GetThread(s);

Thread t1 = new Thread(st);
Thread t2 = new Thread(gt);

//开启线程
t1.start();
t2.start();
}
}


七:线程组

线程组:Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。

默认情况下,所有的线程都属于主线程组。
public final ThreadGroup getThreadGroup():获取线程对应的线程组对象

我们也可以给线程设置分组
Thread(ThreadGroup group, Runnable target)

案例1:创建线程获取对应的线程组对象,并获取名称
案例2:创建线程组对象,给线程分配线程组


package day16.edu_07;

public class MyRunnable implements Runnable{

@Override
public void run() {

}
}


package day16.edu_07;

public class MyThread extends Thread{
@Override
public void run() {

}
}


package day16.edu_07;

public class Test {
public static void main(String[] args) {
// 案例1:创建线程获取对应的线程组对象,并获取名称
MyThread m1 = new MyThread();
MyThread m2 = new MyThread();

//获取上面两个线程对应的线程组对象
ThreadGroup tg1 = m1.getThreadGroup();
ThreadGroup tg2 = m2.getThreadGroup();

//获取线程组对象的名称
System.out.println(tg1.getName());
System.out.println(tg2.getName());

System.out.println("-------------------------");
//案例2:创建线程组对象,给线程分配线程组
//public ThreadGroup(String name)
ThreadGroup tg = new ThreadGroup("大白");

//public Thread(ThreadGroup group,Runnable target)
Thread t3 = new Thread(tg, new MyRunnable());
Thread t4 = new Thread(tg, new MyRunnable());

//获取t3和t4的线程组对象
ThreadGroup tg3 = t3.getThreadGroup();
ThreadGroup tg4 = t4.getThreadGroup();
System.out.println(tg3.getName());
System.out.println(tg4.getName());
}
}


八:线程池

为什么要使用线程池?

程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,
尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。


线程池的特点:

线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池


线程池如何创建?

JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
public static ExecutorService newFixedThreadPool(int nThreads)


package day16.edu_08;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPool {
public static void main(String[] args) {
//线程池如何创建?
//1.调用工厂类Executors
//的public static ExecutorService newFixedThreadPool(int nThreads),返回一个线程池对象
ExecutorService pool = Executors.newFixedThreadPool(2);

//2.提交给线程池两个任务,都是打印0-9
//创建任务
MyRunable m1 = new MyRunable();
MyRunable m2 = new MyRunable();

//3.提交任务
pool.submit(m1);
pool.submit(m2);

//关闭线程池
pool.shutdown();
}
}


package day16.edu_08;

public class MyRunable implements Runnable{

@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"  "+i);
}
}
}


线程池的使用步骤:

1.创建线程池对象

ExecutorService pool = Executors.newFixedThreadPool(2);

2.创建Runnable实例

MyRunnable my = new MyRunnable();

3.提交Runnable实例

pool.submit(my);

pool.submit(my);

4.关闭线程池

pool.shutdown();

案例1:实现Runnable接口实现线程池的使用

案例2:实现Callable接口实现线程池的使用

package com.edu_09;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPool {
public static void main(String[] args) {
//案例2:实现Callable接口实现线程池的使用
//1.创建线程池
ExecutorService pool = Executors.newFixedThreadPool(2);

//创建一个任务
MyCallable my1 = new MyCallable();
MyCallable my2 = new MyCallable();

//3.提交任务
pool.submit(my1);
pool.submit(my2);

//4.关闭线程池
pool.shutdown();

}
}


package com.edu_09;

import java.util.concurrent.Callable;

public class MyCallable implements Callable{
//也是一个任务,只不过这个任务需要执行的方法是call(),这个方法有返回值
@Override
public Object call() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"---"+i);
}
return null;
}
}


案例3:实现Callable接口实现线程池的使用,实现多线程求和,1-10之和,1-100之和

package day16.edu_10;

import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer>{
private int Start;
private int end;
public MyCallable(int Start,int end){
this.Start = Start;
this.end = end;
}

@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < end+1; i++) {
sum+=i;
}
return sum;
}

}


package day16.edu_10;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

//案例3:实现Callable接口实现线程池的使用,实现多线程求和,1-10之和,1-100之和
public class Test {
public static void main(String[] args) throws Exception {
//1.创建线程池
ExecutorService pool = Executors.newFixedThreadPool(2);

//2.创建任务对象,创建任务对象的同时,将参数进行传递
MyCallable m1 = new MyCallable(1, 10);
MyCallable m2 = new MyCallable(1, 100);

//3.提交任务<T> Future<T> submit(Callable<T> task)
Future<Integer> s1 = pool.submit(m1);
Future<Integer> s2 = pool.submit(m2);

//V get()如有必要,等待计算完成,然后获取其结果。
System.out.println(s1.get());
System.out.println(s2.get());

//4.关闭线程池
pool.shutdown();
}
}


九:定时器

Timer

public Timer()构造

public void schedule(TimerTask task, long delay)延迟多久执行任务

public void schedule(TimerTask task,long delay,long period)延迟多久执行任务,并以后每隔多久执行一次

public boolean cancel()取消这个任务

TimerTask

public abstract void run()放的是所要执行的任务代码

案例1:演示以上方法的使用

package com.edu_11;

import java.util.Timer;
import java.util.TimerTask;

public class TimerTest {
public static void main(String[] args) {
//需求:在10秒钟后,在控制台打印一句话,helloworld
//public Timer()构造
Timer t = new Timer();

//public void schedule(TimerTask task, long delay)延迟多久执行任务
t.schedule(new MyTimerTask(t), 10000);

//public void cancel()终止此计时器
//t.cancel();//如果在这里关闭的话,我们还没等任务执行完毕呢,计时器已经被关闭了

}

}

//创建TimerTask的子类
class MyTimerTask extends TimerTask{
private Timer t;
public MyTimerTask(Timer t){
this.t = t;
}

@Override
public void run() {
//此计时器任务要执行的操作。
System.out.println("helloworld");
t.cancel();//当任务被执行完毕之后,关闭定时器
}
}


package com.edu_11;

import java.util.Timer;
import java.util.TimerTask;

//public void schedule(TimerTask task,long delay,long period)
//延迟多久执行任务,并以后每隔多久执行一次
public class TimerTest2 {
public static void main(String[] args) {
//延迟5秒钟,打印,我爱中国,以后每隔一秒打印一次
Timer t = new Timer();

t.schedule(new MyTimerTask2(), 5000, 1000);
/**
* 参数1:要执行的任务
* 参数2:延迟多久执行
* 参数3:执行一次之后,每隔多久重复执行
*/

}

}

class MyTimerTask2 extends TimerTask{
@Override
public void run() {
System.out.println("我爱中国");
}
}


案例2:定时删除文件

所用方法:schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务

package com.edu_12;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class Test {
public static void main(String[] args) throws Exception {
/**
* 案例2:定时删除文件(需要在15:58:00 删除D://a.txt文件)
* 所用方法:schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务
* 时间点:16:30:00
* 任务:删除D://a.txt文件
*/
//创建定时器
Timer t = new Timer();

String time = "2017-05-20 16:31:00";
Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(time);

//所用方法:schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务
t.schedule(new MyTimerTask(), date);
}

}

class MyTimerTask extends TimerTask{

@Override
public void run() {
//任务:删除D://a.txt文件
File file = new File("D://a.txt");
file.delete();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: