学习JAVA多线程之解决线程安全和线程的通信

#近期学习JAVA打卡!
接着上次这几天把多线程差不多看完了,当然也手敲了一遍!
上次学会了创建多线程的两种方式,多线程中Thread类的很多方法
这次学的是:1解决线程安全问题的三种方法
2实现死锁
3线程通信

首先是第一个 解决线程安全的三种方法(也可以说是两种);
方式一:同步代码快
synchronized(同步监视器){
//需要被同步的代码块
}
说明 1.操作共享数据的代码,即为需要被同步的代码 //不能太多也不能太少
2.共享数据:多个线程共同操作的变量 //比如下面的ticket
3.同步监视器 俗称:锁 任何一个类的对象都可以充当 //多个线程公用一把锁

方式二:同步方法
5 同步的方式 解决了线程的安全问题—————好处
操作同步代码时,只能有一个线程参与其他线程等待,相当于是一个单线程过程,效率低

方法三:
使用LOCK锁来解决线程的安全问题 JDK5.0新增

1面试题:synchronized和Lock有什么异同
相同点:都可以解决线程安全问题。
不同点:synchronized机制在执行完相应同步代码以后自动关闭
Lock需要手动启动同步(lock()),手动关闭同步(unlock())

2优先使用顺序
Lock→同步代码快(已经进入了方法体,分配了相应资源)→同步方法(在同步代码外)

然后!!!!
是死锁 实现了死锁

1死锁的理解:不同的线程分别占用对方需要的同步资源不放弃
都在等待对方放弃自己需要的同步资源,形成了死锁

2说明:
1)死锁后,不会出现异常,不会出现提示,只是所有的线程处于阻塞状态,无法继续
2)使用同步时,要避免死锁

package com.lrq.threads;
/*死锁
 * 
 * 1死锁的理解:不同的线程分别占用对方需要的同步资源不放弃
 * 都在等待对方放弃自己需要的同步资源,形成了死锁
 * 
 * 2说明:
 * 1)死锁后,不会出现异常,不会出现提示,只是所有的线程处于阻塞状态,无法继续
 * 2)使用同步时,要避免死锁
 * 
 */
public class DeadLock {
	public static void main(String[] args) {
		StringBuffer a1=new StringBuffer();
		StringBuffer a2=new StringBuffer();
		StringBuffer a3=new StringBuffer();
		
		new Thread() {
			@Override
			public void run() {
				
			synchronized(a1) {
				a1.append("L");
				a2.append("1");
				
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {

					e.printStackTrace();
				}
				
				synchronized(a2) {
					a1.append("R");
					a2.append("2");
				}
				System.out.println(a1);
				System.out.println(a2);
			}
			}
			
			
		}.start();
	new Thread(new Runnable() {
		
		@Override
		public void run() {
			synchronized(a2) {
				a1.append("Q");
				a2.append("3");
				
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {

					e.printStackTrace();
				}
				synchronized(a1) {
					a1.append("S");
					a2.append("4");
				}
				System.out.println(a1);
				System.out.println(a2);
	
			}
		}
	}).start();
}}

第三个 线程的通信
线程通信的例子:使用两个线程打印1-100, 线程1,线程2交替打印
*涉及到的三个方法:
*wait()一旦执行,线程就进入阻塞状态,并且释放同步监视器
*notify()一旦执行,就会释放被wait()的一个线程,如果有多个线程就释放优先级高的
*notifyall()一旦执行,释放所有被wait()的线程
*

  • wait() notify() notifyall()三个方法必须使用在同步代码快或同步方法中
  • wait() notify() notifyall()三个方法的调用者必须是同步代码快或同步方法的同步监视器
  •        否则会出现IllegalMonitorStateException
    
  • wait() notify() notifyall()三个方法定义在java.lang.Object类中
  • 面试题:wait()和sleep()的异同
  • 1.相同点:都可以调用使线程变成阻塞状态
  • 2.不同的:1)两个方法声明的位置不同:Thread类中声明sleep(),Object类中声明wait()
  • 2)调用的要求不同:sleep()可以在任何需要的场景下调用,wait()只能在同步代码快中调用
    
  • 3)关于是否释放同步监视器:如果两个方法都使用在同步代码快和同步方法中,sleep()不会释放锁 wait()会释放锁 
    
class Number implements Runnable{
	private int number=1;
	private Object Obj =new Object();
	@Override
	public void run() {
		while(true) {
			synchronized(Obj) {
				
				Obj.notify();
			if(number<=100) {
		
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				System.out.println(Thread.currentThread().getName()+":"+number);
				number++;
				
				try {
					//调用wait使线程进入阻塞状态 然后去释放另外一个线程
					Obj.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}		
			}else {
				break;
			}	
			}	
		}
	}	
}
public class communicationTest {
	public static void main(String[] args) {
		Number N =new Number();
		Thread T1 =new Thread(N);
		Thread T2 =new Thread(N);
		
		T1.setName("线程一");
		T2.setName("线程二");
		T1.start();
		T2.start();
	}
}
发布了29 篇原创文章 · 获赞 3 · 访问量 862

猜你喜欢

转载自blog.csdn.net/My_name_PeterLiu/article/details/103111665