概念
1.一个对象就是一个线程,多个对象就是多线程,一块资源就是进程,多块资源就是多进程,多个对象抢一块资源就是并发,多个对象抢多块资源就是并行
2.一块资源就是一个或多个共享变量,多个对象共享一块资源就必须要同步锁,否则会变成多个对象每一个对象都有一块资源
3.javaw
4.主线程的入口是main,子线程的入口是run,主线程是特殊的线程,与其他子线程同时进行,不需要和其他子线程抢夺CPU资源,除非遇到线程控制方法。
start开启一条子线程,不影响当前线程运行。
join开启一条子线程后,将这条子线程加入当前线程,必须先执行完这条子线程,当前线程才能继续执行
yeild出让资源给同优先级的子线程,不影响主线程
5.开启的子线程默认是前台线程(不会因为当前线程退出而退出),setDaemon设置为后台线程(当前线程退出,后台线程必须退出),设置后台线程必须在start之前
6.线程的生命周期:
新建:new
就绪:start();一个线程只能开启一次,准备抢资源
运行:抢到资源,开始执行代码块(可能刚执行完一条代码,又被别的线程抢回去了)
阻塞:线程暂停(sleep、wait、join、suspend、IO阻塞…)
死亡:run方法执行完毕,线程退出
线程创建的三种方法
//1.新建一个类继承Thread,重写run方法,创建该类的对象,调用start方法
public class Test{
public static void main(String[] args){
Person per1 = new Person();
Person per2 = new Person();
per1.start();
per2.start();
}
}
class Person extends Thread{
public void run()
}
}
//简写形式
new Thread() {
public void run() {
System.out.println("我是子线程");
}
}.start();
//2.新建一个类实现runnable接口,重写run方法,创建runnable对象,使用runnable对象来创建Thread,调用start方法
public class Test {
public static void main(String[] args) {
Person per = new Person();
Thread th1 = new Thread(per);
Thread th2 = new Thread(per);
th1.start();
th2.start();
}
}
class Person implements Runnable{
public void run() {
}
}
//简写形式
new Thread(new Runnable() {
public void run() {
System.out.println("我是子线程");
}
}).start();
//3.新建一个类实现Callback接口,创建callback实例,用callback对象来创建futuretask实例,用futuretask对象来创建thread实例,调用thread.start方法,如果需要获取结果,可以用futuretask对象调用get方法获取线程返回,但会阻塞当前线程
同步锁
1.把访问到的共享变量全部括起来
2.括起来之后要使用同一把锁(obj、this、类类型)
线程通信(wait、notify方法)
1.必须放在同步锁中
2.调用者必须是锁
3.调用wait进入休眠状态,并释放锁
线程池概念
线程池就是管理线程,是线程的集合,线程池中的线程能够并发执行,提供了两个主要主要方法:
1.execute();开始执行任务
2.shutdown();线程池关闭,线程消失不维护
3.shutdownnow();立即关闭线程池,sleep无法终结
线程池创建
//1.缓冲线程池;第一次可以开启任意个线程,第二次开启如果有空闲的线程,就会去重用它
ExecutorService ctp = Executors.newCachedThreadPool();
ctp.execute(new Runnable() {
@Override
public void run() {
}
});
//2.固定线程:不管开启多少个任务,线程池只会用3条线程来执行,执行完后复用原来3条线程
ExecutorService ftp = Executors.newFixedThreadPool(3);
ftp.execute(new Runnable() {
@Override
public void run() {
}
});
//3.单线程:只开启一条线程,相当于固定线程的参数1
ExecutorService ste = Executors.newSingleThreadExecutor();
ste.execute(new Runnable() {
@Override
public void run() {
}
});
//4.定时器:
ScheduledExecutorService stp =Executors.newScheduledThreadPool(1);
System.out.println("延迟任务5秒后开启");
stp.schedule(new Runnable() {
@Override
// 延迟任务
public void run() {
System.out.println("任务开启");
}
}, 5000, TimeUnit.MILLISECONDS);
//关闭定时器
stp.shutdown();
ScheduledExecutorService stp1 = Executors.newScheduledThreadPool(1);
stp1.scheduleAtFixedRate(new Runnable() {
int i = 5;
@Override
// 周期任务定时器
public void run() {
if (i == 0) {
System.out.println("没了");
stp1.shutdown();
} else {
System.out.println("离世界末日还有" + (i--) + "秒");
}
}
//6s后开启任务,每隔1s执行一次任务,ms单位
}, 6000, 1000, TimeUnit.MILLISECONDS);
//5.Timer类也有定时器功能
Timer timer = new Timer();
timer.schedule(new TimerTask() {
int i = 5;
@Override
public void run() {
System.out.println("1s执行1次," + i + "s后关闭定时器");
if ((--i) == 0) {
System.out.println("关闭定时器");
timer.cancel();
}
}
}, 3000, 1000);
//定时器必须是单个线程
小练习
1.龟兔赛跑
2.生产者消费者(几条线程、共享变量)