一、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();
}
}