Thread学习之三(线程安全)

  1. 线程安全java

    1. 缘由:当多个线程访问一个共享的资源时,会产生线程安全的问题。c++

    2. 解决方法:用synchronized关键字作为多线程并发环境的执行有序性的保证手段之一。当一段代码会修改共享变量,这一段代码成为互斥区或临界区,为了保证共享变量的正确性,synchronized标示了临界区。典型的用法以下:安全

      synchronized(锁){   //这个锁是共享对象多线程

           临界区代码   并发

      }ide

    3. /**
       * 两个线程共同打印a~z,考虑线程安全
       *
       */
      public class PrintLetters implements Runnable {
      
      	private char c = 'a';
      	
      	public synchronized boolean print() {
      		
      		if (c <= 'z') {
      			System.out.println(Thread.currentThread().getName() + " --- " + c);
      			
      			try {
      				Thread.currentThread().sleep(100);
      			} catch (InterruptedException e) {
      				e.printStackTrace();
      			}
      			
      			c++;
      			
      			return true;
      		}
      		
      		return false;
      	}
      	
      	@Override
      	public void run() {
      		boolean flag = print();
      		
      		while (flag) {
      			flag = print();
      		}
      
      	}
      
      	public static void main(String[] args) {
      		PrintLetters printLetters = new PrintLetters();
      		
      		Thread thread1 = new Thread(printLetters);
      		Thread thread2 = new Thread(printLetters);
      		
      		thread1.setName("线程-1");
      		thread2.setName("线程-2");
      		
      		thread1.start();
      		thread2.start();
      	}
      }

      上面代码属于public synchronized void add(int num)状况,其锁就是这个方法所在的对象。同理,若是方法是public  static synchronized void add(int num),那么锁就是这个方法所在的class。spa

  2. 线程间的相互做用:线程之间须要一些协调通讯,来共同完成一件任务。能够调用java.lang.Object中的wait()、notify()和notifyAll()方法,这些方法是final的,不能被重写。.net

    1. wait():使当前线程进入放弃对象锁进入wait pool中等待。直到其余线程调用notify()或notifyAll()方法唤醒该线程。要确保线程调用wait()方法时拥有对象锁,即wait()方法必须在synchronized方法或者synchronized方法块中调用。
      线程

    2. notify()、notifyAll()code

      1. notify():唤醒一个处于等待当前对象锁的线程。若是多个线程处于等待状态,会随机选择一个线程唤醒。同时,被唤醒的线程暂时不能被执行,须要等到当前线程放弃对象锁。见:http://my.oschina.net/u/1757476/blog/420169  线程的生命周期。

      2. notifyAll():唤醒全部等待当前对象锁的线程,变成等待该对象上的锁。一旦该对象被解锁,它们就会去竞争。

      3. /**
         * 模拟卖票:刘、关、张三人买票,售票员只有一张5元零钱,票价5元;张飞拿20元排在刘、关前面,刘、关二人各拿了5元。
         * 线程间的通讯
         */
        public class TicketHouse implements Runnable {
        	
        	private int fiveCount = 1, tenCount = 0, twentyCount = 0;
        	
        	public synchronized void buy() {
        		String name = Thread.currentThread().getName();
        		
        		//张飞 20元
        		if ("张飞".equals(name)) {
        			if (fiveCount < 3) {
        				try {
        					System.out.println("5元面值:" + fiveCount + ". 张飞等待...");
        					wait();
        					
        					System.out.println("卖一张票给" + name + ",找零15. 5元面值:" + fiveCount);
        				} catch (InterruptedException e) {
        					e.printStackTrace();
        				}
        			}
        		} else if ("关羽".equals(name) || "刘备".equals(name)) {
        			fiveCount++;
        			System.out.println("卖一张票给" + name + ",钱正好. 5元面值:" + fiveCount);
        		}
        		
        		if (fiveCount == 3) {
        			notifyAll();
        		}
        	}
        
        	@Override
        	public void run() {
        		buy();
        	}
        
        	public static void main(String[] args) {
        		Runnable runnable = new TicketHouse();
        		
        		Thread th1 = new Thread(runnable);
        		Thread th2 = new Thread(runnable);
        		Thread th3 = new Thread(runnable);
        		
        		th1.setName("刘备");
        		th2.setName("关羽");
        		th3.setName("张飞");
        		
        		th3.start();
        		th1.start();
        		th2.start();
        	}
        }
      4. /**
         * 两个线程交替打印a~z
         *
         */
        public class PrintLetters2 implements Runnable {
        	private char c = 'a';
        	
        	@Override
        	public void run() {
        		while (c <= 'z') {
        			print();
        		}
        	}
        	
        	public synchronized void print() {
        		if (c <= 'z') {
        			System.out.println(Thread.currentThread().getName() + "---" + c);
        			c++;
        			
        			notify();
        			
        			try {
        				wait();
        			} catch (InterruptedException e) {
        				e.printStackTrace();
        			}
        		}
        	}
        	
        	public static void main(String[] args) {
        		Runnable runnable = new PrintLetters2();
        		
        		Thread th1 = new Thread(runnable);
        		Thread th2 = new Thread(runnable);
        		
        		th1.setName("线程-1");
        		th2.setName("线程-2");
        		
        		th1.start();
        		th2.start();
        	}
        }
相关文章
相关标签/搜索