一、线程间的共享
1、synchronized内置锁
对象锁,锁的是类的对象实例。
类锁 ,锁的是每个类的的Class对象,每个类的的Class对象在一个虚拟机中只有一个,所以类锁也只有一个。
2、volatile关键字
适合于只有一个线程写,多个线程读的场景,因为它只能确保可见性。
3、ThreadLocal
线程变量。可以理解为是个map,类型 Map<Thread,Integer>
二、线程间协作
1、轮询
难以保证及时性,资源开销很大,
2、等待和通知
wait() 对象上的方法,将是当前执行线程进行等待。
notify/notifyAll 对象上的方法 发送信号量,唤醒线程。
代码示例:
/**
* @Auther: BlackKingW
* @Date: 2019/4/14 12:09
* @Description:
*/
public class Express {
public final static String CITY = "ShangHai";
private int km;/*快递运输里程数*/
private String site;/*快递到达地点*/
public Express() {
}
public Express(int km, String site) {
this.km = km;
this.site = site;
}
/* 变化公里数,然后通知处于wait状态并需要处理公里数的线程进行业务处理*/
public synchronized void changeKm(){
this.km = 101;
notifyAll();
//其他的业务代码
}
/* 变化地点,然后通知处于wait状态并需要处理地点的线程进行业务处理*/
public synchronized void changeSite(){
this.site = "BeiJing";
notify();
}
public synchronized void waitKm(){
while(this.km<=100) {
try {
wait();
System.out.println("check km thread["+Thread.currentThread().getId()
+"] is be notifed.");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("the km is"+this.km+",I will change db.");
}
public synchronized void waitSite(){
while(CITY.equals(this.site)) {
try {
wait();
System.out.println("check site thread["+Thread.currentThread().getId()
+"] is be notifed.");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("the site is"+this.site+",I will call user.");
}
}
/**
* @Auther: BlackKingW
* @Date: 2019/4/14 12:09
* @Description:
*/
public class TestWN {
private static Express express = new Express(0,Express.CITY);
/*检查里程数变化的线程,不满足条件,线程一直等待*/
private static class CheckKm extends Thread{
@Override
public void run() {
express.waitKm();
}
}
/*检查地点变化的线程,不满足条件,线程一直等待*/
private static class CheckSite extends Thread{
@Override
public void run() {
express.waitSite();
}
}
public static void main(String[] args) throws InterruptedException {
for(int i=0;i<3;i++){//三个线程
new CheckSite().start();
}
for(int i=0;i<3;i++){//里程数的变化
new CheckKm().start();
}
Thread.sleep(1000);
express.changeKm();//快递地点变化
}
}
等待和通知的标准范式
等待方:
- 获取对象的锁;
- 循环里判断条件是否满足,不满足调用wait方法,
- 条件满足执行业务逻辑
通知方来说
- 获取对象的锁;
- 改变条件
- 通知所有等待在对象的线程
notify和notifyAll应该用谁?
应该尽量使用notifyAll,使用notify因为有可能发生信号丢失的的情况
3、join()方法
thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。
比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。
代码示例:
/**
* @Auther: BlackKingW
* @Date: 2019/4/14 12:09
* @Description:
*/
public class UseJoin {
//
static class JumpQueue implements Runnable {
private Thread thread;//用来插队的线程
public JumpQueue(Thread thread) {
this.thread = thread;
}
public void run() {
try {
System.out.println(thread.getName()+" will be join before "
+Thread.currentThread().getName());
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" terminted.");
}
}
public static void main(String[] args) throws Exception {
Thread previous = Thread.currentThread();//现在是主线程
for (int i = 0; i < 10; i++) {
//i=0,previous 是主线程,i=1;previous是i=0这个线程
Thread thread =
new Thread(new JumpQueue(previous), String.valueOf(i));
System.out.println(previous.getName()+" jump a queue the thread:"
+thread.getName());
thread.start();
previous = thread;
}
SleepTools.second(2);//让主线程休眠2秒
System.out.println(Thread.currentThread().getName() + " terminate.");
}
}
问题:调用yield() 、sleep()、wait()、notify()等方法对锁有何影响?
线程在执行yield()以后,持有的锁是不释放的
sleep()方法被调用以后,持有的锁是不释放的
调动方法之前,必须要持有锁。调用了wait()方法以后,锁就会被释放,当wait方法返回的时候,线程会重新持有锁
调动方法之前,必须要持有锁,调用notify()方法本身不会释放锁的
大家有什么疑问可以加我微信进行沟通哈~