• Android多线程研究(3)——线程同步和互斥及死锁


    为什么会有线程同步的概念呢?为什么要同步?什么是线程同步?先看一段代码:

    package com.maso.test;
    
    public class ThreadTest2 implements Runnable{
    	private TestObj testObj = new TestObj();
    	
    	public static void main(String[] args) {
    		ThreadTest2 tt = new ThreadTest2();
    		Thread t1 = new Thread(tt, "thread_1");
    		Thread t2 = new Thread(tt, "thread_2");
    		t1.start();
    		t2.start();
    	}
    
    	@Override
    	public void run() {
    		
    		for(int j = 0; j < 10; j++){
    			int i = fix(1);
    			try {
    				Thread.sleep(1);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			
    			System.out.println(Thread.currentThread().getName() + " :  i = " + i);
    		}
    		
    	}
    	
    	public int fix(int y){
    		return testObj.fix(y);
    	}
    	
    	public class TestObj{
    		int x = 10;
    		
    		public int fix(int y){
    			return x = x - y;
    		}
    	}
    	
    	
    }
    
    输出结果后,就会发现变量x被两个线程同时操作,这样就很容易导致误操作。如何才能解决这个问题呢?用线程的同步技术,加上synchronized关键字

    	public synchronized int fix(int y){
    		return testObj.fix(y);
    	}
    加上同步后,就可以看到有序的从9输出到-10.

    如果加到TestObj类的fix方法上能不能实现同步呢?

    	public class TestObj{
    		int x = 10;
    		
    		public synchronized int fix(int y){
    			return x = x - y;
    		}
    	}
    如果将synchronized加到方法上则等价于

    	synchronized(this){
    		
    	}
    可以判断出两个线程使用的TestObj类的同一个实例testOjb,所以后实现同步,但是输出的结果却不是理想的结果。这是因为当A线程执行完x = x - y后还没有输出则B线程已经进入开始执行x = x - y.

    所以像下面这样输出就不会有什么问题了:

    	public class TestObj{
    		public TestObj(){
    			System.out.println("调用了构造函数");
    		}
    		
    		int x = 10;
    		
    		public synchronized int fix(int y){
    			x = x - y;	
    			System.out.println(Thread.currentThread().getName() + " :  x = " + x);
    			return x;
    		}
    	}
    如果将外部的fix方法修改如下:

    	public int fix(int y){
    		ax++ ;
    		if(ax%2 == 0){
    		return testObj.fix(y, testObj.str1);
    		}else{
    			return testObj.fix(y, testObj.str2);
    		}
    	}
    	public class TestObj{
    		String str1 = "a1";
    		String str2 = "a2";
    		
    		public TestObj(){
    			System.out.println("调用了构造函数");
    		}
    		
    		int x = 10;
    		
    		public int fix(int y, String str){
    			synchronized (str) {
    				x = x - y;	
    				System.out.println(Thread.currentThread().getName() + " :  x = " + x);
    			}
    			return x;
    		}
    	}
    此时synchronized中的str对象不是同一个对象,所以两个线程所持有的对象锁不是同一个,这样就不能实现同步。要实现线程之间的互斥就要使用同一个对象锁。

    什么是死锁呢?举个例子就是比如你和同学租了个两室的房子,你拿着你房子的钥匙,你同学拿着他房子的钥匙,现在你在房子等你同学将他的钥匙给你然后你进他房子,你同学在他的房子等你将钥匙给他然后他进你的房子,这样就死锁了。

    package com.maso.test;
    
    public class ThreadDieSock implements Runnable {
        private int flag = 1;
        private Object obj1 = new Object(), obj2 = new Object();
    
        public void run() {
            System.out.println("flag=" + flag);
            if (flag == 1) {
                synchronized (obj1) {
                    System.out.println("我已经锁定obj1,休息0.5秒后锁定obj2去!");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (obj2) {
                        System.out.println("1");
                    }
                }
            }
            if (flag == 0) {
                synchronized (obj2) {
                    System.out.println("我已经锁定obj2,休息0.5秒后锁定obj1去!");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (obj1) {
                        System.out.println("0");
                    }
                }
            }
        }
    
        public static void main(String[] args) {
            ThreadDieSock run01 = new ThreadDieSock();
            ThreadDieSock run02 = new ThreadDieSock();
            run01.flag = 1;
            run02.flag = 0;
            Thread thread01 = new Thread(run01);
            Thread thread02 = new Thread(run02);
            System.out.println("线程开始喽!");
            thread01.start();
            thread02.start();
        }
    }





  • 相关阅读:
    Windows共享上网的做法
    如何花更少的时间学习更多的知识
    因权限引起的svn提交失败的错误及其解决办法
    ArcGIS二次开发入门(一)
    GeoTiff如何存储颜色表的研究
    html5文件夹上传源码
    vue文件夹上传源码
    前端文件夹上传源码
    asp.net文件夹上传源码
    使用webuploader实现大文件上传分片上传
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6468941.html
Copyright © 2020-2023  润新知