JAVE SE 学习day_09:sleep线程阻塞方法、守护线程、join协调线程同步方法、synchronized关键字解决多线程并发安全问题

一、sleep线程阻塞方法

static void sleep(long ms)
Thread提供的静态方法sleep可以让运行该方法的线程阻塞指定毫秒,超时后线程会自动回到RUNNABLE状态,等待再次获取时间片并发运行。

		/*
		 * 实现一个倒计时程序,程序启动后要求输入一个整数,然后每秒递减,到
		 * 0时输出“时间到”
		 */
		System.out.println("请输入你想要进行倒计时的数字:");
		Scanner scan = new Scanner(System.in);
		int num = scan.nextInt();
		System.out.println(num+"秒倒计时程序开始了。。。");
		for(;num>=0;num--){//for(;;){  等同于while(true){
			try{
				Thread.sleep(1000);//阻塞5秒
				if(num>=1){
					System.out.println(num);
				}
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
		System.out.println("时间到程序结束了。。。");

sleep方法要求我们必须处理InterruptedException异常,当一个线程调用sleep方法 处于阻塞过程中,此时该线程的interrupt()方法被调用时会中断其sleep阻塞,此时该方法就会抛出这个异常。

Thread lin = new Thread(){
			public void run(){
				System.out.println("lin:after work,sleep...");
				try{
					Thread.sleep(10000000);
				}catch(InterruptedException e){
					System.out.println("lin:what hapenny,what hapenny,");
				}
				System.out.println("lin:wake up");
			}
		};
		Thread huang = new Thread(){
			public void run(){
				System.out.println("黄宏开始砸墙");
				for(int i=0;i<5;i++){
					System.out.println("80!80!");
					try{
						Thread.sleep(1000);
					}catch(InterruptedException e){
					//确保不会被中断	
					}
				}
				System.out.println("哐当~");
				System.out.println("黄宏:搞定~");
				lin.interrupt();//中断lin线程的睡眠阻塞
			}
		};
		lin.start();
		huang.start();

二、守护线程

守护线程是通过普通线程调用setDaemon方法设置而来,因此创建和使用其实与普通线程无异。但是结束时机上有一点不同,即进程的结束。
进程结束:当进程中的所有普通线程都结束时,进程就会结束,此时所有正在运行的守护线程都会被强制中断。
注:设置守护线程必须位于该线程启动之前

		Thread rose  = new Thread(){
			public void run(){
				for(int i = 0;i<5;i++){
					System.out.println("rose:let me go!");
					try{
						Thread.sleep(1000);
					}catch(InterruptedException e){
						
					}
				}
				System.out.println("A A A A A A~噗通");
			}
		};
		
		Thread joke = new Thread(){
			public void run(){
				while(true){
					try{
						Thread.sleep(1000);
						System.out.println("joke:you jump,i jump");
						}catch(InterruptedException e){
							
						}
				
				}
			}
		};
		
		rose.start();
		//设置守护线程必须位于该线程启动之前
		joke.setDaemon(true);
		joke.start();

三、join协调线程同步方法

void join()
该方法是用来协调线程之间的同步运行

多线程的运行方式:
异步运行:并发运行本身就是异步运行,各干各的
同步运行:使多个线程运行时存在先后顺序进行

public class JoinDemo {
	static boolean isFinish = false;//标识图片是否下载完毕
	
	public static void main(String[] args) {
		Thread download = new Thread(){
			//boolean isFinish = false;
			/*
			 * java中有一个语法要求:当一个方法的局部内部类中使用了这个方法的其他局部
			 * 变量时,该变量必须声明为final的
			 * 以当前案例为例:
			 * main方法的局部内部类download中使用main方法的其他局部变量isFinish
			 * 那么isFinish就必须声明为final
			 * 在JDK8之后,final可以不写,但该特性依然存在,因此不可以在局部内部类中
			 * 对该变量赋值
			 */
			public void run(){
				System.out.println("开始下载");
				for(int i=0;i<100;i++){
					System.out.println("down:"+i+"%");
					try{
						Thread.sleep(50);
					}catch(InterruptedException e){
						
					}
				}
				System.out.println("图片下载完成");
				isFinish = true;//下载完毕
			}
		};
		
		
		Thread show = new Thread(){
			public void run(){
				try{
					System.out.println("show:开始显示文字");
					Thread.sleep(100);
					System.out.println("show:文字显示完毕");
					System.out.println("show:图片加载");
					
					System.out.println("show:等待down。。。");
					download.join();//show线程进入阻塞状态,在download线程结束为止
					System.out.println("show:等待down完毕");
					
					if(!isFinish){
						throw new RuntimeException("图片加载失败");
					}
					System.out.println("show:图片显示完毕");
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		};
		
		download.start();
		show.start();

四、synchronized关键字与多线程并发安全问题

多线程并发安全问题

  • 当多个线程并发操作同一临界资源时,由于线程切换的时机不确定,导致操作过程的顺序* 错乱,出现严重的后果。
  • 临界资源:同时只能被单个线程操作的资源。
4.1 同步方法

当一个方法被synchronized修饰后,该方法称为同步方法。即:多个线程不能 同时在方法内部执行。将异步调用方法改为同步调用方法可以解决并发安全问题。

	public static void main(String[] args) {
		Table table=new Table();
		Thread t1 = new Thread(){
			public void run(){
				while(true){
					int bean = table.getbean();
					Thread.yield();
					System.out.println(getName()+":"+bean);
				}
			}
		};
		Thread t2 = new Thread(){
			public void run(){
				while(true){
					int bean = table.getbean();
					Thread.yield();
					System.out.println(getName()+":"+bean);
				}
			}
		};
		t1.start();
		t2.start();
	}
}

class Table{
	private int beans = 20;//20个豆子
	/**
	 * 当一个方法被synchronized修饰后,该方法称为同步方法。即:多个线程不能
	 * 同时在方法内部执行。将异步调用方法改为同步调用方法可以解决并发安全问题
	 */
	public synchronized int getbean(){
		//synchronized
		if(beans==0){
			throw new RuntimeException("没有豆子了");
		}
		Thread.yield();//主动让出CPU时间
		return beans--;
	}
4.2 同步块

语法:
synchronized(同步监视器对象){
需要多线程同步运行的代码片段
}

*

  • 同步块可以更加准确地锁定需要同步运行的代码片段,有效的缩小同步范围 可以保证并发安全的前提下提高并发效率

同步块使用时必须指定同步监视器对象:()中的内容

  • 该对象科可以是java中任何对象的实例,但需要保证一点:多个需要同步执行的线程看到的这个对象必须是同一个。
	public static void main(String[] args) {
//		Shopping sp1 = new Shopping();
//		Shopping sp2 = new Shopping();
		Shopping sp = new Shopping();
		Thread t1 = new Thread(){
			public void run(){
			//	sp1.buy();//两个线程没有进入同一个对象,不存在抢的问题
				sp.buy();
			}
		};
		Thread  t2 = new Thread(){
			public void run(){
			//	sp2.buy();
				sp.buy();
			}
		};
		t1.start();
		t2.start();
	}
}
class Shopping{
	//public  void buy(){//没有任何同步约束时性能最好,但是存在安全问题
	/*
	 * 在方法上使用synchronized,那么指定的同步器监视对象就是this
	 */
	//public synchronized void buy(){//解决了并发安全问题,但是性能不好
	public  void buy(){
		try {
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+"slecting");
			Thread.sleep(5000);
			/*
			 * 同步块使用时必须指定同步监视器对象:()中的内容
			 * 该对象科可以是java中任何对象的实例,但需要保证一点:多个需要同步
			 * 执行的线程看到的这个对象必须是同一个
			 */
			//synchronized(this){
			//synchronized(new Object()){//没有同步效果
				System.out.println(t.getName()+"trying");
				Thread.sleep(5000);
			//}
			System.out.println(t.getName()+"结账");
		}catch(Exception e){
			
		}
4.3 静态方法上修饰

成员方法上使用synchronized修饰后,锁对象为该方法所属对象this
但是静态方法不同,静态方法所属类,全局就一个,因为静态方法上使用synchronize 后该方法一定具有同步效果,而他指定的锁对象为当前类的类对象(Class的一个实例)
即在静态方法中使用同步块时,指定的锁对象通常也是当前类的类对象。
获取当前类的类对象的方式为:类名.clsss

public class SyncDemo3 {

	public static void main(String[] args) {
		Boo b = new Boo();
		Thread t1 = new Thread(){
			public void run(){
				b.dosome();
			}
		};
		Thread t2 = new Thread(){
			public void run(){
				b.dosome();
			}
		};
		
		t1.start();
		t2.start();
	}

}

class Boo{
	//public synchronized static void dosome(){
	public  static void dosome(){
		/*
		 *在静态方法中使用同步块时,指定的锁对象通常也是当前类的类对象,而获取
		 *当前类的类对象的方式为:类名.clsss
		 */
		synchronized(Boo.class){
			try{
				Thread t = Thread.currentThread();
				System.out.println(t.getName()+"starting ..");
				Thread.sleep(3000);
				System.out.println(t.getName()+"over...");
			}catch(Exception e){
			}
		}
	}
}
4.4 互斥锁

当使用多个synchronized锁定多个代码片段时,这些synchronized指定的同步监视器对象是同一个时,那么这些代码片段就是互斥的,多个线程不能同时执行写几个代码片段。
有synchronized且共同指向同一对象时,进行该对象方法运行才会进行锁的识别和等待。

public class SyncDemo4 {
	public static void main(String[] args) {
		Foo f = new Foo();
//		Foo f1 = new Foo();
//		Foo f2 = new Foo();
		Thread t1 = new Thread(){
			public void run(){
//				f1.methodA();//与下面线程的f2.methodb无互斥现象,锁的对象不同
				f.methodA();
			}
		};
		Thread t2 = new Thread(){
			public void run(){
//				f2.methodB();
				f.methodB();
			}
		};
		t1.start();
		t2.start();
	}
}

class Foo{
	//public synchronized void methodA(){
	public void methodA(){
		synchronized (this){
		/*
		 * //这样写依然与下方的b方法有互斥性,因为这里指定的同步监视器对象是this,也就
		 * 是methoda方法所属对象,而methodb上直接写synchronized时指定的也是this
		 * 
		 * 那么此时两个线程分别调用同一个Foo对象的methoda和methodb方法时就互斥
		 */
			try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+":执行a方法");
			Thread.sleep(5000);
			System.out.println(t.getName()+":执行a方法over");
			}catch(Exception e){	
			}
		}
	}
	public synchronized void methodB(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+":执行b方法");
			Thread.sleep(5000);
			System.out.println(t.getName()+":执行b方法over");
		}catch(Exception e){
			
		}
	}
}
练习
	/*5*/
		System.out.println("number:");
		Scanner scan1 = new Scanner(System.in);
		int num1 = scan1.nextInt();
		System.out.println(num1+"");
		for(;num1>=0;num1--){
			try{
				Thread.sleep(1000);
				if(num1>=1){
					System.out.println(num1);
				}
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
		System.out.println("over");
		/*4*/
		System.out.println("number:");
		Scanner scan2 = new Scanner(System.in);
		int num2 = scan2.nextInt();
		System.out.println(num2+"daoshu");
		for(;num2>=0;num2--){
			try{
				Thread.sleep(1000);
				if(num2>=1){
					System.out.println(num2);
				}
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
		System.out.println("over");
		/*3*/
		System.out.println("number:");
		Scanner scan3 = new Scanner(System.in);
		int num3 = scan3.nextInt();
		System.out.println(num3+"daojishi");
		for(;num3>=0;num3--){
			try{
				Thread.sleep(1000);
				if(num3>=1){
					System.out.println(num3);
				}
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
		System.out.println("over");
		/*4*/
		System.out.println("number:");
		Scanner scan4 = new Scanner(System.in);
		int num4 = scan4.nextInt();
		System.out.println(num4+"daojishi");
		for(;num4>=0;num--){
			try{
				Thread.sleep(1000);
				if(num4>=1){
					System.out.println(num4);
				}
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
		System.out.println("over");
		/*5*/
		System.out.println("number:");
		Scanner scan0 = new Scanner(System.in);
		int num0 = scan0.nextInt();
		System.out.println(num0+"daojishi");
		for(;num0>=0;num0--){
			try{
				Thread.sleep(1000);
				if(num0>=1){
					System.out.println(num0);
				}
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
		System.out.println("over");
public static void main(String[] args) {
		Table table=new Table();
		Thread t1 = new Thread(){
			public void run(){
				while(true){
					int bean = table.getbean();
					Thread.yield();
					System.out.println(getName()+":"+bean);
				}
			}
		};
		Thread t2 = new Thread(){
			public void run(){
				while(true){
					int bean = table.getbean();
					Thread.yield();
					System.out.println(getName()+":"+bean);
				}
			}
		};
		t1.start();
		t2.start();
}
/*5*/
class table1{
	private int beans = 20;
	public synchronized int getbean(){
		if(beans==0){
			throw new RuntimeException("not have bean");
		}
		Thread.yield();
		return beans--;
	}
}
/*4*/
class table2{
	private int beans = 20;
	public synchronized int getbean(){
		if(beans==0){
			throw new RuntimeException("no bean");
		}
		Thread.yield();
		return beans--;
	}
}
/*3*/
class table3{
	private int beans=10;
	public synchronized int getbean(){
		if(beans==0){
			throw new RuntimeException("no bean");
		}
		Thread.yield();
		return beans--;
	}
}
/*2*/
class table4{
	private int beans=10;
	public synchronized int getbean(){
		if(beans==0){
			throw new RuntimeException("no bean ");
		}
		Thread.yield();
		return beans--;
	}
}
/*1*/
class table5{
	private int beans=15;
	public synchronized int getbean(){
		if(beans==0){
			throw new RuntimeException("no bean ");
		}
		Thread.yield();
		return beans--;
	}
}

	public static void main(String[] args) {
//		Shopping sp1 = new Shopping();
//		Shopping sp2 = new Shopping();
		Shopping sp = new Shopping();
		Thread t1 = new Thread(){
			public void run(){
			//	sp1.buy();//两个线程没有进入同一个对象,不存在抢的问题
				sp.buy();
			}
		};
		
		Thread  t2 = new Thread(){
			public void run(){
			//	sp2.buy();
				sp.buy();
			}
		};
		t1.start();
		t2.start();
	}
/*5*/
 class shop{
	public void buy(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+"slecting");
			Thread.sleep(5000);
			synchronized(this){
				System.out.println(t.getName()+"trying");
				Thread.sleep(5000);
			}
			System.out.println(t.getName()+"结账");
		}catch(Exception e){
			
		}
	}
}
/*4*/
class shop2{
	public void buy(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+"slecting");
			Thread.sleep(5000);
			synchronized(this){
				System.out.println(t.getName()+"trying");
				Thread.sleep(5000);
			}
			System.out.println(t.getName()+"结账");
		}catch(Exception e){
			
		}
	}
}
/*3*/
class shop3{
	public void buy(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+"slecting");
			Thread.sleep(5000);
			synchronized(this){
				System.out.println(t.getName()+"trying");
				Thread.sleep(5000);
			}
			System.out.println(t.getName()+"结账");
		}catch(Exception e){
			
		}
	}
}
/*2*/
class shop4{
	public void buy(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+"slecting");
			Thread.sleep(5000);
			synchronized (this){
				System.out.println(t.getName()+"trying");
				Thread.sleep(5000);
			}
			System.out.println(t.getName()+"结账");
		}catch(Exception e){
			
		}
	}
}
/*1*/
class shop0{
	public void buy(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+"slecting");
			Thread.sleep(5000);
			synchronized (this){
				System.out.println(t.getName()+"trying");
				Thread.sleep(5000);
			}
			System.out.println(t.getName()+"结账");
		}catch(Exception e){
			
		}
	}
}
/*5*/
class boo1{
	public synchronized static void dosome(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+"starting ..");
			Thread.sleep(3000);
			System.out.println(t.getName()+"over...");
		}catch(Exception e){
		}
	}
}
/*4*/
class boo2{
	public static void dosome(){
		synchronized(boo2.class){
			try{
				Thread t = Thread.currentThread();
				System.out.println(t.getName()+"starting ..");
				Thread.sleep(3000);
				System.out.println(t.getName()+"over...");
			}catch(Exception e){
			}
		}
	}
}
/*3*/
class boo3{
	public synchronized static void dosome(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+"starting ..");
			Thread.sleep(3000);
			System.out.println(t.getName()+"over...");
		}catch(Exception e){
		}
	}
}
/*2*/
class boo4{
	public static void dosome(){
		synchronized(boo4.class){
			try{
				Thread t = Thread.currentThread();
				System.out.println(t.getName()+"starting ..");
				Thread.sleep(3000);
				System.out.println(t.getName()+"over...");
			}catch(Exception e){
			}
		}
	}
}
/*1*/
class boo0{
	//public synchronized static void dosone{
	public static void dosome(){
		synchronized(boo0.class){
			try{
				Thread t = Thread.currentThread();
				System.out.println(t.getName()+"starting ..");
				Thread.sleep(3000);
				System.out.println(t.getName()+"over...");
			}catch(Exception e){
			}
		}
	}
	//}
}
/*5*/
class foo1{
	public void a(){
		synchronized(foo1.class){
			try{
				Thread t = Thread.currentThread();
				System.out.println(t.getName()+":执行a方法");
				Thread.sleep(5000);
				System.out.println(t.getName()+":执行a方法over");
			}catch(Exception e){
				
			}
		}
	}
	public synchronized void b(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+":执行b方法");
			Thread.sleep(5000);
			System.out.println(t.getName()+":执行b方法over");
		}catch(Exception e){
			
		}
	}
}
/*4*/
class foo2{
	public synchronized void a(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+":执行a方法");
			Thread.sleep(5000);
			System.out.println(t.getName()+":执行a方法over");
		}catch(Exception e){
			
		}
	}
	public synchronized void b(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+":执行b方法");
			Thread.sleep(5000);
			System.out.println(t.getName()+":执行b方法over");
		}catch(Exception e){
			
		}
	}
}
/*3*/
class foo3{
	public void a(){
		synchronized(foo3.class){
			try{
				Thread t = Thread.currentThread();
				System.out.println(t.getName()+":执行a方法");
				Thread.sleep(5000);
				System.out.println(t.getName()+":执行a方法over");
			}catch(Exception e){
				
			}
		}
	}
	public synchronized void b(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+":执行b方法");
			Thread.sleep(5000);
			System.out.println(t.getName()+":执行b方法over");
		}catch(Exception e){
			
		}
	}
}
/*2*/
class foo4{
	public void a(){
		synchronized(foo4.class){
			try{
				Thread t = Thread.currentThread();
				System.out.println(t.getName()+":执行a方法");
				Thread.sleep(5000);
				System.out.println(t.getName()+":执行a方法over");
			}catch(Exception e){
				
			}
		}
	}
	public synchronized void b(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+":执行b方法");
			Thread.sleep(5000);
			System.out.println(t.getName()+":执行b方法over");
		}catch(Exception e){
			
		}
	}
}
/*1*/
class foo0{
	//public synchronized void a(){
	public void a(){
		synchronized(foo0.class){
			try{
				Thread t = Thread.currentThread();
				System.out.println(t.getName()+":执行a方法");
				Thread.sleep(5000);
				System.out.println(t.getName()+":执行a方法over");
			}catch(Exception e){
				
			}
		}
	}
	//}
	public synchronized void b(){
		try{
			Thread t = Thread.currentThread();
			System.out.println(t.getName()+":执行b方法");
			Thread.sleep(5000);
			System.out.println(t.getName()+":执行b方法over");
		}catch(Exception e){
			
		}
	}
}

	public static void main(String[] args) {
		Foo f = new Foo();
//		Foo f1 = new Foo();
//		Foo f2 = new Foo();
		Thread t1 = new Thread(){
			public void run(){
//				f1.methodA();//与下面线程的f2.methodb无互斥现象,锁的对象不同
				f.methodA();
			}
		};
		Thread t2 = new Thread(){
			public void run(){
//				f2.methodB();
				f.methodB();
			}
		};
		
		t1.start();
		t2.start();
		/*5*/
		foo0 f11 = new foo0();
		Thread t11 = new Thread(){
			public void run(){
				f11.a();
			}
		};
		Thread t21 = new Thread(){
			public void run(){
				f11.b();
			}
		};
		t11.start();
		t21.start();
		/*4*/
		foo4 f21= new foo4();
		foo4 f22 = new foo4();
		Thread t12 = new Thread(){
			public void run(){
				f21.a();
			}
		};
		Thread t22 = new Thread(){
			public void run(){
				f22.b();
			}
		};
		t12.start();
		t22.start();
		/*3*/
		foo3 f3 = new foo3();
		Thread t31 = new Thread(){
			public void run(){
				f3.a();
			}
		};
		Thread t32 = new Thread(){
			public void run(){
				f3.b();
			}
		};
		t31.start();
		t32.start();
		/*2*/
		foo2 f41= new foo2();
		foo2 f42 = new foo2();
		Thread t41 = new Thread(){
			public void run(){
				f21.a();
			}
		};
		Thread t42 = new Thread(){
			public void run(){
				f22.b();
			}
		};
		t41.start();
		t42.start();
		/*1*/
		foo1 f5 = new foo1();
//		foo1 f51 = new foo1();
//		foo1 f52 = new foo1();
		Thread t51 = new Thread(){
			public void run(){
//				f51.methodA();
				f5.a();
			}
		};
		Thread t52 = new Thread(){
			public void run(){
//				f52.methodB();
				f5.b();
			}
		};
		t51.start();
		t52.start();
	}

}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值