java多线程简单案例入门(四)

2014-11-23 23:13:29 · 作者: · 浏览: 3
不安全的。

5.1 TestThread8.java

package com.thread;

public class TestThread8 {
	
	public static void main(String[] args) {
	
			ThreadDemo8 t = new ThreadDemo8();
			new Thread(t).start();
			new Thread(t).start();
			new Thread(t).start();
			new Thread(t).start();
			
		}

	}

	class ThreadDemo8 implements Runnable{
		
		int tickets = 100 ;
			public void run(){
				
				while(tickets>0){					
						
					/*线程休眠10毫秒,模拟出线程不安全的情况出现。不加sleep()也是线程不安全的,加了sleep()则不安全的结果会更容易出现。*/
					try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();};
					System.out.println("run():"+Thread.currentThread().getName()+"is saling ticket "+tickets--);
					
					
				}
			}
			
	}

结果截图:

\


为了确保while(tickets>0)和{system.out.println(tickets--)}代码块操作的原子性,用synchronized(对象)来实现,看下面程序。

5.2 TestThread9.java

package com.thread;

public class TestThread9 {

	
	public static void main(String[] args) {
		ThreadDemo9 t = new ThreadDemo9();
		new Thread(t).start();
		new Thread(t).start();
		new Thread(t).start();
		new Thread(t).start();
		
	}

}

class ThreadDemo9 implements Runnable{
	
	int tickets = 100 ;
	String str = "";
		public void run(){
			
			synchronized (str) { /* synchronized (任意对象)可实现代码块的原子性*/
				
				while(tickets>0){						
					//线程休眠10毫秒,模拟出线程不安全的情况出现。不加sleep()也是线程不安全的,加了sleep()则不安全的结果会更容易出现。
					try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();};
					System.out.println("run():"+Thread.currentThread().getName()+"is saling ticket "+tickets--);			
				}
			}
			
		}
		
}

运行结果:

\

注意 :用synchronized(任一对象名){代码块} ,可实现代码块原子性操作,确保代码块的同步。因为每一个对象都有一个标志位,0或者1.

当str标志位为1时,线程进入代码块,str标志位立刻变为0,变为阻塞状态,其他线程就被阻塞。直到synchronized代码块执行完,str的标志位变为1,才会取消阻塞状态,java程序才能切换到其他线程执行。

str的标志位又称:监视器的锁旗标。

当其他线程访问到str监视器时,若str监视器的锁旗标为0,则其他线程将会进入一个因str监视器锁旗标而产生的等待线程池中。直到str监视器的锁旗标变为1时,才可能享有str监视器的锁旗标。

注意:String str = "" ; 要放在run()方法外。

还可以使用同步函数达到同步效果,看代码:

5.3 TestThread10.java

package com.thread;

public class TestThread10 {

	
	public static void main(String[] args) {
		ThreadDemo10 t = new ThreadDemo10();
		new Thread(t).start();
		new Thread(t).start();
		new Thread(t).start();
		new Thread(t).start();
		
	}

}

class ThreadDemo10 implements Runnable{
	
	int tickets = 100 ;
	String str = "";
	public void run(){
		sale();
		
	}
	public synchronized void sale(){
		
		while(tickets>0){						
			//线程休眠10毫秒,模拟出线程不安全的情况出现。不加sleep()也是线程不安全的,加了sleep()则不安全的结果会更容易出现。
			try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();};
			System.out.println("run():"+Thread.currentThread().getName()+"is saling ticket "+tickets--);			
		}
		
	}
		
}

注意: 在 方法名前加上 synchronized 关键字,则 sale()方法是线程安全的,监视器是 this 对象。

即可使用同步代码块来实现线程之间的同步,也可以使用同步函数来实现线程之间的同步。

怎样使得同步代码块和同步函数保持同步? 使用同一个监视器this即可。看下面的程序。

5.4 TestThread11.java

package com.thread;

public class TestThread11 {
	
	public static void main(String[] args) {
		
		ThreadDemo11 t = new ThreadDemo11();				
		new Thread(t).start();
		try { Thread.sleep(1);} catch (Exception e) { e.printStackTrace();}
		t.str = "method";		
		new Thread(t).start();
		
	}

}

class ThreadDemo11 implements Runnable{
	
	int tickets = 100 ;
	String str = "";
	public void run(){
		
		if (str.equals("method")) {
			sale();
		}else {