zoukankan      html  css  js  c++  java
  • Java同步synchronized与死锁

    多个线程要操作同一资源时就有可能出现资源的同步问题

    同步就是指多个操作在同一个时间段内只能有一个线程进行,其他线程要等待此线程完成之后才可以继续执行。

    解决资源共享的同步操作,可以使用同步代码块同步方法两种方式完成。

    <1>同步代码块

    所谓代码块就是指使用“{}"括起来的一段代码,根据其位置和声明的不同,可以分为普通代码块、构造块、静态块3种,如果在代码块上加上synchronized关键字,则此代码块就称为同步代码块。

    package java_thread;
    //=================================================
    // File Name       :	Runnable_demo2
    //------------------------------------------------------------------------------
    // Author          :	Common
    
    
    // 类名:MyThread_2
    // 属性:
    // 方法:
    class MyThread_2 implements Runnable{
    	private int ticket = 5;	
    	
    	@Override
    	public void run() {								//覆写Thread类中的run()方法
    		// TODO 自动生成的方法存根
    		for (int i=0;i<10;i++){
    			synchronized (this) {					//设置需要同步的操作
    				if(ticket>0){
    					try{
    						Thread.sleep(300);
    					}catch(InterruptedException e){
    						e.printStackTrace();
    					}
    					System.out.println("卖票:ticket="+ticket--);
    				}
    			}
    //			this.sale();												//调用同步方法
    		}
    	}
    	
    }
    
    
    
    //主类
    //Function        : 	Thread_demo2
    public class Runnable_demo2 {
    
    	public static void main(String[] args) {
    		// TODO 自动生成的方法存根
    		MyThread_2 mt = new MyThread_2();	//实例化Runnable子类对象
    		Thread t1 = new Thread(mt);							//实例化Thread类对象
    		Thread t2 = new Thread(mt);							//实例化Thread类对象
    		Thread t3 = new Thread(mt);							//实例化Thread类对象
    		t1.start();																	//启动线程
    		t2.start();																	//启动线程
    		t3.start();																	//启动线程
    	}
    
    }
    

     

    package java_thread;
    
    class Output{
    	public void output(String name){
    		int len = name.length();
    		synchronized(this){		//不能使用name,因为“输出1”和"输出2"两个字符串不是同一个对象
    			for(int i=0;i<len;i++){
    				System.out.print(name.charAt(i));
    			}
    			System.out.println();
    		}
    	}
    }
    
    
    public class Huchi {
    
    	private void init(){
    		final Output outputer = new Output();
    		//线程1
    		new Thread(new Runnable(){
    			@Override
    			public void run() {								//覆写Thread类中的run()方法
    				while(true){
    						try {
    							Thread.sleep(10);
    						} catch (InterruptedException e) {
    							// TODO 自动生成的 catch 块
    							e.printStackTrace();
    						}
    						//new Output().output("输出1");		//也不能new对象,new对象的话,this就不代表同一个对象了
    						outputer.output("输出1");
    				}
    			}
    		}).start();
    		
    		//线程2
    		new Thread(new Runnable(){
    			@Override
    			public void run() {								//覆写Thread类中的run()方法
    				while(true){
    						try {
    							Thread.sleep(10);
    						} catch (InterruptedException e) {
    							// TODO 自动生成的 catch 块
    							e.printStackTrace();
    						}
    						//new Output().output("输出1");		//也不能new对象,new对象的话,this就不代表同一个对象了
    						outputer.output("输出2");
    				}
    			}
    		}).start();
    		
    	}
    	
    	public static void main(String[] args) {
    		// TODO 自动生成的方法存根
    		new Huchi().init();
    	}
    
    }
    

     

    <2>同步方法

    也可以使用synchronized关键字将一个方法声明成同步方法

    //=================================================
    // File Name       :	Thread_demo
    //------------------------------------------------------------------------------
    // Author          :	Common
    
    
    // 接口名:MyThread
    // 属性:
    // 方法:
    class MyThread_2 implements Runnable{
    	private int ticket = 5;	
    	
    	@Override
    	public void run() {								//覆写Thread类中的run()方法
    		// TODO 自动生成的方法存根
    		for (int i=0;i<10;i++){
    			this.sale();												//调用同步方法
    		}
    	}
    	
    	public synchronized void sale(){			//声明同步方法
    		if(ticket>0){
    			try{
    				Thread.sleep(300);
    			}catch(InterruptedException e){
    				e.printStackTrace();
    			}
    			System.out.println("卖票:ticket="+ticket--);
    		}
    	}
    	
    }
    
    
    
    //主类
    //Function        : 	Thread_demo2
    public class Runnable_demo2 {
    
    	public static void main(String[] args) {
    		// TODO 自动生成的方法存根
    		MyThread_2 mt = new MyThread_2();	//实例化Runnable子类对象
    		Thread t1 = new Thread(mt);							//实例化Thread类对象
    		Thread t2 = new Thread(mt);							//实例化Thread类对象
    		Thread t3 = new Thread(mt);							//实例化Thread类对象
    		t1.start();																	//启动线程
    		t2.start();																	//启动线程
    		t3.start();																	//启动线程
    	}
    
    }
    

    死锁就是指两个线程都在等待彼此先完成,造成了程序的停滞,一般程序的死锁都是在程序运行时出现的。

    多个线程共享同一资源时需要进行同步,以保证资源操作的完整性,但是过多的同步就有可能产生死锁。

    生产者不断生产,消费者不断取走生产者生产的产品

    //=================================================
    // File Name       :	ThreadInfo_demo
    //------------------------------------------------------------------------------
    // Author          :	Common
    
    
    // 类名:Info
    // 属性:
    // 方法:
    class Info{
    	private String name = "张三";
    	private String content = "学生";
    	private boolean flag = false;
    	
    	public synchronized void set(String name,String content){	//设置信息名称及内容
    		if(!flag){																	//标志位为false,不可以生产,在这里等待取走
    			try{
    				super.wait();												//等待消费者取走
    			}catch(InterruptedException e){
    				e.printStackTrace();
    			}
    		}	
    		this.setName(name);								//设置信息名称							
    		try{
    			Thread.sleep(300);									//加入延迟
    		}catch(InterruptedException e){
    			e.printStackTrace();
    		}
    		this.setContent(content);						//设置信息内容
    		flag = false;													//标志位为true,表示可以取走
    		super.notify();											//唤醒等待线程
    	}
    	
    	public synchronized void get(){			//取得信息内容
    		if(flag){															//标志位为true,不可以取走
    			try{
    				super.wait();										//等待生产者生产
    			}catch(InterruptedException e){
    				e.printStackTrace();
    			}
    		}		
    		try {
    			Thread.sleep(300);									//加入延迟
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println(this.getName()+"-->"+this.getContent());	//输出信息
    		flag = true;													//修改标志位为true,表示可以生产
    		super.notify();											//唤醒等待线程
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getContent() {
    		return content;
    	}
    
    	public void setContent(String content) {
    		this.content = content;
    	}
    	
    }
    
    //类名:Producer
    //属性:
    //方法:
    class Producer implements Runnable{		//定义生产者线程
    
    	private Info info = null;								//保存Info引用
    	
    	public Producer(Info info) {						//构造函数
    		super();
    		this.info = info;
    	}
    
    	@Override
    	public void run() {
    		// TODO 自动生成的方法存根
    		boolean flag = false;
    		for(int i=0;i<50;i++){				//50次反复修改name和content的值
    			if(flag){
    				this.info.set("张三", "学生");
    				flag = false;
    			}else{
    				this.info.set("李四", "老师");
    				flag = true;
    			}
    		}
    	}
    	
    }
    
    //类名:Consumer
    //属性:
    //方法:
    class Consumer implements Runnable{		//定义生产者线程
    
    	private Info info = null;								//保存Info引用
    	
    	public Consumer(Info info) {						//构造函数
    		super();
    		this.info = info;
    	}
    
    	@Override
    	public void run() {
    		// TODO 自动生成的方法存根
    		for(int i=0;i<50;i++){				//50次反复修改name和content的值
    			try {
    				Thread.sleep(100);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			this.info.get();
    		}
    	}
    	
    }
    
    //主类
    //Function        : 	ThreadInfo_demo
    public class ThreadInfo_demo {
    
    	public static void main(String[] args) {
    		// TODO 自动生成的方法存根
    		Info i = new Info();
    		Producer pro = new Producer(i);
    		Consumer con = new Consumer(i);
    		new Thread(pro).start();
    		new Thread(con).start();
    	}
    
    }
    

    停止线程运行

    在多线程的开发中可以通过设置标志位的方式停止一个线程的运行

    //=================================================
    // File Name       :	ThreadInfo_demo
    //------------------------------------------------------------------------------
    // Author          :	Common
    
    
    // 类名:MYThread
    // 属性:
    // 方法:
    class MYThread implements Runnable{
    	
    	private boolean flag = true;			//定义标志位属性
    	
    	@Override
    	public void run() {
    		// TODO 自动生成的方法存根
    		int i = 0;
    		while(this.flag){								//循环输出
    			while(true){
    				System.out.println(Thread.currentThread().getName()+(i++));	//输出当前线程名称
    			}
    		}
    	}
    	
    	public void stop(){							//编写停止方法
    		this.flag = false;							//修改标志位
    	}
    	
    }
    
    //主类
    //Function        : 	ThreadStop_demo
    public class ThreadStop_demo {
    
    	public static void main(String[] args) {
    		// TODO 自动生成的方法存根
    		MYThread my = new MYThread();
    		Thread t = new Thread(my,"线程");
    		t.start();
    		my.stop();
    	}
    
    }
    

    互斥性

    output1和output2两段代码互斥,检查的都是outputer这个对象

    package java_thread;
    
    class Output{
    	public void output(String name){
    		int len = name.length();
    		synchronized(this){		//不能使用name,因为“输出1”和"输出2"两个字符串不是同一个对象
    			for(int i=0;i<len;i++){
    				System.out.print(name.charAt(i));
    			}
    			System.out.println();
    		}
    	}
    	
    	public synchronized void output2(String name){	//output1和output2两段代码互斥,检查的都是outputer这个对象
    		int len = name.length();
    		for(int i=0;i<len;i++){
    			System.out.print(name.charAt(i));
    		}
    		System.out.println();
    	}
    }
    
    
    public class Huchi {
    
    	private void init(){
    		final Output outputer = new Output();
    		//线程1
    		new Thread(new Runnable(){
    			@Override
    			public void run() {								//覆写Thread类中的run()方法
    				while(true){
    						try {
    							Thread.sleep(10);
    						} catch (InterruptedException e) {
    							// TODO 自动生成的 catch 块
    							e.printStackTrace();
    						}
    						//new Output().output("输出1");		//也不能new对象,new对象的话,this就不代表同一个对象了
    						outputer.output("输出1");
    				}
    			}
    		}).start();
    		
    		//线程2
    		new Thread(new Runnable(){
    			@Override
    			public void run() {								//覆写Thread类中的run()方法
    				while(true){
    						try {
    							Thread.sleep(10);
    						} catch (InterruptedException e) {
    							// TODO 自动生成的 catch 块
    							e.printStackTrace();
    						}
    						//new Output().output("输出1");		//也不能new对象,new对象的话,this就不代表同一个对象了
    						outputer.output2("输出2");
    				}
    			}
    		}).start();
    		
    	}
    	
    	public static void main(String[] args) {
    		// TODO 自动生成的方法存根
    		new Huchi().init();
    	}
    
    }
    

     

    static静态方法调用的对象是字节码对象,所以要把output1的this改成Output.class

    package java_thread;
    
    class Output{
    	public void output1(String name){
    		int len = name.length();
    		synchronized(this){		//不能使用name,因为“输出1”和"输出2"两个字符串不是同一个对象
    			for(int i=0;i<len;i++){
    				System.out.print(name.charAt(i));
    			}
    			System.out.println();
    		}
    	}
    	
    	//static静态方法调用的对象是字节码对象,所以要把output1的this改成Output.class
    	public static synchronized void output3(String name){	//output1和output3不同步,除非把output1的this改成Output.class
    		int len = name.length();
    		for(int i=0;i<len;i++){
    			System.out.print(name.charAt(i));
    		}
    		System.out.println();
    	}
    	
    }
    
    
    public class Huchi {
    
    	private void init(){
    		final Output outputer = new Output();
    		//线程1
    		new Thread(new Runnable(){
    			@Override
    			public void run() {								//覆写Thread类中的run()方法
    				while(true){
    						try {
    							Thread.sleep(10);
    						} catch (InterruptedException e) {
    							// TODO 自动生成的 catch 块
    							e.printStackTrace();
    						}
    						//new Output().output("输出1");		//也不能new对象,new对象的话,this就不代表同一个对象了
    						outputer.output1("输出1");
    				}
    			}
    		}).start();
    		
    		//线程2
    		new Thread(new Runnable(){
    			@Override
    			public void run() {								//覆写Thread类中的run()方法
    				while(true){
    						try {
    							Thread.sleep(10);
    						} catch (InterruptedException e) {
    							// TODO 自动生成的 catch 块
    							e.printStackTrace();
    						}
    						//new Output().output("输出1");		//也不能new对象,new对象的话,this就不代表同一个对象了
    						outputer.output3("输出2");
    				}
    			}
    		}).start();
    		
    	}
    	
    	public static void main(String[] args) {
    		// TODO 自动生成的方法存根
    		new Huchi().init();
    	}
    
    }
    

     this      Output.class

        

    面试题:子线程循环 10 次,接着主线程循环 100,接着又回到子线程循环 10 次,接着再回到主线程又循环 100,如此循环50 次,请写出程序

    package java_thread;
    
    import java.util.concurrent.atomic.AtomicInteger;
    //张孝祥java面试题28
    //子线程循环 10 次,接着主线程循环 100,接着又回到子线程循环 10 次,接着再回到主线程又循环 100,如此循环50 次,请写出程序
    
    public class TraditionalThreadCommunication {
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		final Business business = new Business();
    		new Thread(
    				new Runnable() {
    					@Override
    					public void run() {
    						for(int i=1;i<=50;i++){
    							business.sub(i);
    						}
    					}
    				}
    		).start();
    		
    		for(int i=1;i<=50;i++){
    			business.main(i);
    		}
    		
    	}
    }
    
    class Business {
    	private boolean bShouldSub = true;
    	public synchronized void sub(int i){
    		while(!bShouldSub){
    			try {
    				this.wait();
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		for(int j=1;j<=10;j++){
    			System.out.println("sub thread sequence of " + j + ",loop of " + i);
    		}
    		bShouldSub = false;
    		this.notify();
    	}
    	  
    	public synchronized void main(int i){
    		while(bShouldSub){
    			try {
    				this.wait();
    			} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		for(int j=1;j<=100;j++){
    			System.out.println("main thread sequence of " + j + ",loop of " + i);
    		}
    		bShouldSub = true;
    		this.notify();
    	}
    }
    
  • 相关阅读:
    电路中的VCC和VDD
    动态数码管 什么是位选 段选
    pytest文档62-内置fixture之request
    pytest文档61-fixture之name参数使用别名
    pytest文档60-pytest.main()的使用
    python笔记49-yaml文件中变量的使用(锚点& 与 引用*)
    python笔记48-面试题:m1={'a':1,'b':2,'c':1} 将同样的value的key集合在list里,输出{1:['a','c'],2:['b']}
    jenkins学习15-Allure报告不用登陆也能给领导看
    python接口自动化35-pyppeteer-install下载没反应,r.html.render() 下载无反应问题解决
    kvm内存优化--KSM
  • 原文地址:https://www.cnblogs.com/tonglin0325/p/5253434.html
Copyright © 2011-2022 走看看