Java多线程

多线程的概念

进程、线程、多线程的概念

进程: 正在进行中的程序
线程:进程中一个负责程序执行的控制单元(执行路径)。一个进程中可以有多个执行路径,称之为多线程。一个进程中至少要有一个线程。
优点:解决了多部分代码同时运行的问题。
弊端:线程太多,会导致效率的降低。

Java VM启动的时候会有一个进程java.exe,该进程中至少一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称之为主线程。jvm启动不止一个线程,还有负责垃圾回收机制的线程。
所以JVM启动时,至少有两个线程:
1.执行main函数的线程,该线程的任务代码都定义在main函数中。
2.负责垃圾回收的线程。

创建线程方式一

步骤:
1.继承Thread类
2.重写Thread类中的run方法(Thread类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码 。该存储功能就是run方法也就是说Thread类中的run方法,用于      存储线程要运行的代码)
3.调用线程的start方法,该方法有两个作用,启动线程和调用run方法
class TestWork {

	public static void main(String[] args) {

		ThreadDemo t = new ThreadDemo();
		
		t.start();  //调用start()方法,启动线程
		
		for(int x = 0 ; x < 60 ; x++) {
			
			System.out.println("main......."+x);
			
		}
		
	}

}

class ThreadDemo extends Thread {
	
	//继承Thread类时,要重写run方法
	public void run() {
		
		for(int x = 0 ; x < 60 ; x++) {
			
			System.out.println("Thread......."+x);
			
		}
		
	}
	
}
运行结果每一次都不同?
多个线程都获取cpu的执行权,cpu执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个程序正在运行。(多核除外)cpu在做着快速切换,已达到看上去是同时运行的效果。这就是多线程的一个 特性,随机性。
线程都有自己默认的名称,Thread-编号,编号从0开始
static Thread currentThread():获取当前线程对象
getName():获取线程名称
class TestWork {

	public static void main(String[] args) {

		ThreadDemo t1 = new ThreadDemo("Thread--1");
		ThreadDemo t2 = new ThreadDemo("Thread--2");
		
		t1.start();  //调用start()方法,启动线程
		t2.start();
		
		for(int x = 0 ; x < 60 ; x++) {
			
			System.out.println("main......."+x);
			
		}
		
	}

}

class ThreadDemo extends Thread {
	private String name;  //给线程自定义一个名字
	
	ThreadDemo(String name) {
		
		super(name);   //Thread类里面定义好了构造方法直接调用
		
	}
	
	public void run() {
		for(int x = 0 ; x < 40 ; x++)
			System.out.println(this.getName()+":"+x); //获取线程名字的方法等同于Thread.currentThread().getName()
		
	}
	
}

创建线程方式二

步骤:
1.定义类实现Runnable接口
2.覆盖Runnable接口中的run方法,将线程要运行的代码存放在该run方法中
3.通过Thread类建立线程对象
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数(自定义的run方法所属对象是Runnable接口的子类对象 ,要让让线程去执行指定对象的run方法,就       必须明确该run方法所属对象)
5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
优点:避免了单继承的局限性,将线程的任务从线程的子类中分离出来,进行了单独的封装,按照面向对象的思想将任务封装成对象。
class TestWork {

	public static void main(String[] args) {

		ThreadDemo son = new ThreadDemo();  
		
		//将Runnable接口的子类对象传递给Thread类的构造函数
		Thread t1 = new Thread(son);
		Thread t2 = new Thread(son);
		Thread t3 = new Thread(son);
		Thread t4 = new Thread(son);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
		
	}

}

class ThreadDemo implements Runnable {
	
	private int num = 100;   //定义一个变量并赋值100,
	
	public void run() {
		
		while(true) {
			if(num > 0)  // 对变量进行判断,大于0则执行下面的代码
				System.out.println(Thread.currentThread().getName()+"--num"+num--);  //num变量赋值后减1
		}
		
	}
	
}

线程安全问题

线程安全问题产生的原因

class TestWork {

	public static void main(String[] args) {

		ThreadDemo son = new ThreadDemo();  
		
		//将Runnable接口的子类对象传递给Thread类的构造函数
		Thread t1 = new Thread(son);
		Thread t2 = new Thread(son);
		Thread t3 = new Thread(son);
		Thread t4 = new Thread(son);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
		
	}

}

class ThreadDemo implements Runnable {
	
	private int num = 100;
	
	public void run() {
		
		while(true) {
			if(num > 0) {
				try {
					Thread.sleep(10);  //调用Thread类里面的sleep方法,让线程等待一段时间。
				} catch (InterruptedException e) {   //sleep方法声明了异常,但是ThreadDemo的父类没有声明,所以这里这能try/catch
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"--num"+num--);
				
			}
				
		}
		
	}
	
}

通过对线程创建方式二里的程序多次执行发现,出现了不同线程输出num为负数的情况。因为当线程2执行num--之前,线程0,1,3都通过了if的判断,此时此刻拿着num为2的线程2执行num--后,其它线程开始一次执行,所以就出现了为负数的情况。
线程安全问题产生的原因:
当多条语句在操作同一个线程共享的数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程就已经参与了进来,导致共享 数据的错误

解决方案

对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行
Java对于多线程的安全问题提供了专业的解决方法,同步代码块。
格式:
synchronized(对象) {
  
  需要被同步的代码
  }
优点:解决了多线程的安全问题
缺点:多线程比较多时,较为消耗资源,每个线程都需要判断
注意:使用同步代码块必须要有两个或者以上的线程,必须多个线程使用同一个锁
class TestWork {

	public static void main(String[] args) {

		ThreadDemo son = new ThreadDemo();  
		
		//将Runnable接口的子类对象传递给Thread类的构造函数
		Thread t1 = new Thread(son);
		Thread t2 = new Thread(son);
		Thread t3 = new Thread(son);
		Thread t4 = new Thread(son);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
		
	}

}

class ThreadDemo implements Runnable {
	
	private int num = 100;
	Object obj = new Object(); //建立一个同步代码块锁
	
	public void run() {
		
		while(true) {
			
			//同步代码被多个线程共享的部分
			synchronized(obj) {
				if(num > 0) {
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					  }
					System.out.println(Thread.currentThread().getName()+"--num"+num--);
				
				}
			}
				
		}
		
	}
	
}

因为有同步代码块的原因,先抢到cpu执行权的线程,进来。其它的只能等进锁的线程执行完才能进去。
创建一个银行程序,有两个储户往银行里面存钱,分别存300,每次100,存3次。
1.明确哪些代码是多线程运行代码
2.明确共享数据
3.明确多线程运行代码中哪些语句是操作共享数据的
class TestWork {

	public static void main(String[] args) {

		Cus c = new Cus();
		
		Thread t1 = new Thread(c);
		Thread t2 = new Thread(c);
		
             //开启两个线程
		t1.start();
		t2.start();
		
	}

}

class Bank {
	private int sum;
	
	Object obj = new Object();
	

    //创建一个存钱的方法
	public void add(int m) {
		synchronized(obj) {
		sum = sum +m;
		
		System.out.println(Thread.currentThread().getName()+"--money"+sum);
		}
	}
	
	
}

class Cus implements Runnable {
	
	private Bank b = new Bank();  //创建对象,以便在run方法里面调用存钱的方法
	
	public void run() {
		

             //用for循环来设定往里存放数据的次数
		for(int x = 0 ; x < 3 ; x++) {
			
			b.add(100);
			
		}
		
	}
	
}

该程序还能再到函数上加上synchronized修饰符,因为整个函数都是共享数据,称之为同步函数
public synchronized void add(int m) {
		//synchronized(obj) {
		sum = sum +m;
		
		System.out.println(Thread.currentThread().getName()+"--money"+sum);
		//}
	}
同步函数和同步代码块的区别
1.同步函数的锁是固定的this。
2.同步代码块的锁是任意的对象。
由于同步函数的锁是固定的this,同步代码块的锁是任意的对象,那么如果同步函数和同步代码块都使用this作为锁,可以实现同步
class TestWork {

	public static void main(String[] args) {

		Ticket1 c = new Ticket1();
		
		Thread t1 = new Thread(c);
		Thread t2 = new Thread(c);
		
		t1.start();
		try {
			Thread.sleep(10);  //让主线程等待,因为t1有可能开启了之后没有抢到cpu执行权,让主线程继续往下执行把flag改为flase,以至于两个线程还是用同一个同步代码块。
		}catch(Exception e) {
			
		}
		c.setBool(false);   //把标记改为false让t2区执行同步函数
		t2.start();
		
	}

}


class Ticket1 implements Runnable {
	private int tick = 100;
	private boolean flag = true;   //定义一个标记变量,让t1和t2分道扬镳
	Object obj = new Object();
	
	public void setBool(boolean flag) {
		this.flag = flag;
		
	}
	
	public void run() {
		if(flag) {
			while(true) {
				
				synchronized(this) {
					if(tick > 0) {
						try {
							Thread.sleep(10);  
						}catch(Exception e) {
							
						}
						System.out.println(Thread.currentThread().getName()+":ticket--"+tick--);
					}
				}
				
			}
		}else {
			
			while(true)
				show();
			
		}
		
	}
	
      //定义一个同步函数,让t2进来
	public synchronized void show() {
		if(tick > 0) {
			try {
				Thread.sleep(10);  
			}catch(Exception e) {
				
			}
			System.out.println(Thread.currentThread().getName()+":ticket--"+tick--);
		}
		
		
	}
	
}

静态的同步函数使用的锁是该函数所属字节码文件对象,可以用getClass方法获取,也可以用当前类名.class表示。

多线程下的单例设计模式

单例设计模式下的懒汉式存在安全问题,可以使用同步函数解决,但是synchronized Single getInstance()这种形式使用起来效率太低,如下改动,即可太高效率
class Single {

	private Single() {
		
	}
	
	private static Single s = null;
	
	public static Single getInstance() {
		if(s == null) {   //如果对象已经存在了,就能直接获取不需要再经过下面的代码,提高效率
			synchronized(Single.class) { //因为存在都通过第一个if判断的情况,那么会建立多个对象。所以必须加锁
	                     if(s == null)
                                   s = new Single();
                        }
                }
                return s;
        }
 }

死锁

同步中嵌套同步,如下示例
class DeadLock implements Runnable {
	private boolean flag;
	
	DeadLock(boolean flag) {
		
		this.flag = flag;
		
	}
	public void run() {
		//锁里面还有一把锁
		if(flag) {
			synchronized(Lock.l1) {
				System.out.println(Thread.currentThread().getName()+"--l1");
				
				synchronized(Lock.l2) {
					System.out.println(Thread.currentThread().getName()+"--l2");
				}
			}
		} else {
			
			synchronized(Lock.l2) {
				System.out.println(Thread.currentThread().getName()+"--l2");
				synchronized(Lock.l1) {
					System.out.println(Thread.currentThread().getName()+"--l1");
				}
			}
			
		}
		
	}
	
}


//定义两把不同的锁,方便使用
class Lock {
	
	static Lock l1 = new Lock();
	static Lock l2 = new Lock();
	
}

class Synchronized {
	
	public static void main(String[] args) {
		DeadLock d1 = new DeadLock(true);
		DeadLock d2 = new DeadLock(false);
		
		Thread t1 = new Thread(d1);
		Thread t2 = new Thread(d2);
		
		t1.start();
		t2.start();
		
	}
	
}

为什么会造成死锁现象?
线程t1执行l2里面的代码,必须要拿到l2;线程t2要执行l1里面的代码,必须要拿到l1;当线程开启,t1首先拿到l1,t2则拿到l2,所以t1进入不到l2,t2页进入不到l1。

线程间通信

线程间通信涉及到的方法

线程间通讯:其实就是多个线程在操作同一个资源,但是操作的动作不同。
等待/唤醒机制涉及方法:
wait():       让线程处于冻结状态,被wait的线程会被存储到线程池中
notify():     唤醒线程池中的一个线程(任何一个都有可能)
notifyAll():唤醒线程池中的所有线程。
注意:
都使用在同步中,因为要对持有监视器的线程操作,所以要使用在同步中,只有同步才具有锁。
为什么这些操作线程的方法定义在Object类?
 因为这些方法在操作同步中线程时,都必须要标识他们所操作线程只有的锁,只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。也就是说,等待和唤醒必须是同一个锁而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。
class Resource {
	
	private String name;
	private String sex;
	private boolean flag = false;  //定义一个标记用来判断线程是否要等待
	
	public synchronized void set(String name,String sex) {
		
		if(flag)  //如果flag为true则输入线程等待
			try {
				this.wait();
			} catch(Exception e) {
				
			}
		this.name = name;
		this.sex = sex;
		
		flag = true;  //当线程输入了资源后,把标记改为true让输出线程输出资源
		this.notify();
	}
	
	public synchronized void out() {
		
		if(!flag)   //如果!flag是为假则线程等待
			try {
				this.wait();
			}catch(Exception e) {
				
			}
		System.out.println("name:"+name+" -- sex:"+sex);
			
		flag = false;  //输出完资源之后把flag改为fale
		this.notify(); //唤醒正在等待的输入线程。
		
	}
	
}

class Input implements Runnable {
	
	private Resource r;  //定义一个引用r
	
	Input(Resource r) {
		this.r = r;
	}
	
	public void run() {
		
		int x = 0;
		while(true) {
			
			//循环输入两个组不同的数据
			if(x == 0) {
				
				r.set("Jack", "男");
			}else {
				r.set("Moli", "女");
			}
			
			x = (x+1)%2;
			
		}
		
	}
	
}

class Output implements Runnable {
	
	private Resource r;
	
	Output(Resource r) {
		this.r = r;
	}
	
	public void run() {
		
		while(true) {
			
			r.out();
		}
		
	}
	
}

class TestWork {
	
	public static void main(String[] args) {
		
		Resource r = new Resource(); //创建资源对象
		
		Input in = new Input(r);  //资源对象作为参数,传入
		Output out = new Output(r);
		
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(out);
		
		t1.start();
		t2.start();
		
	}
	
}
多个生产者以及 消费者的问题:
class Resource {
	
	private String name;
	private int count;
	private boolean flag = false;  //定义一个标记用来判断线程是否要等待
	
	public synchronized void set(String name) {
		
		if(flag)  //如果flag为true则输入线程等待
			try {
				this.wait();
			} catch(Exception e) {
				
			}
		this.name = name+count++;
		System.out.println(Thread.currentThread().getName()+"--生产者--"+this.name);
		
		flag = true;  //当线程输入了资源后,把标记改为true让输出线程输出资源
		this.notify();
	}
	
	public synchronized void out() {
		
		if(!flag)   //如果!flag是为假则线程等待
			try {
				this.wait();
			}catch(Exception e) {
				
			}
		System.out.println(Thread.currentThread().getName()+"--消费者--"+this.name);
			
		flag = false;  //输出完资源之后把flag改为fale
		this.notify(); //唤醒正在等待的输入线程。
		
	}
	
}

class Input implements Runnable {
	
	private Resource r;  //定义一个引用r
	
	Input(Resource r) {
		this.r = r;
	}
	
	public void run() {
		
		while(true) {
			r.set("啤酒");
		}
		
	}
	
}

class Output implements Runnable {
	
	private Resource r;
	
	Output(Resource r) {
		this.r = r;
	}
	
	public void run() {
		
		while(true) {
			
			r.out();
		}
		
	}
	
}

class TestWork {
	
	public static void main(String[] args) {
		
		Resource r = new Resource(); //创建资源对象
		
		Input in = new Input(r);  //资源对象作为参数,传入
		Output out = new Output(r);
		
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(in);
		Thread t3 = new Thread(out);
		Thread t4 = new Thread(out);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
	
}
为什么有同步锁,有wait(),notify()方法还是出现了安全问题?
假设:
1.线程Thread-0获取到cpu执行权进入到锁,生产了啤酒1,将flag设置为true,重新获取到执行权回到if判断语句。由于flag已变为ture,所以执行wait方法。然后Thread-1获取到CPU执行权,同样要执行wait方法。
2.线程Thread-2获取到cpu执行权进入到锁,由于flag为true,所以消费了啤酒1,把flag改为false,然后唤醒了Thread-0,但是没有获取到执行权。回到if判断语句,!false为真, 所以Thread-2执行wait方法。接着线程Thread-3获取到了CPU执行权,同样也被wait了。
3.唤醒的Thread-0因为已经被if语句判断过了,所以直接往下面执行代码,生产啤酒2,唤醒Thread-1。同理,Thread-也直接生产啤酒3,唤醒了Thread-2,导致啤酒2没被消费。
4.以此类推,接来下被唤醒的Thread-2消费了,啤酒3。Thread-3也消费了啤酒3。
If判断语句只能判断以此,故用while()循环判断。
注意:
由上面的“假设”可以推断,在while()循环中会出现死锁的情况,故把notify()改为notifyAll()方法
class Resource {
	
	private String name;
	private int count;
	private boolean flag = false;  //定义一个标记用来判断线程是否要等待
	
	public synchronized void set(String name) {
		
		while(flag)  //如果flag为true则输入线程等待
			try {
				this.wait();
			} catch(Exception e) {
				
			}
		this.name = name+count++;
		System.out.println(Thread.currentThread().getName()+"--生产者--"+this.name);
		
		flag = true;  //当线程输入了资源后,把标记改为true让输出线程输出资源
		this.notifyAll();  //唤醒所有等待的线程,防止4个线程都出现等待的状况
	}
	
	public synchronized void out() {
		
		while(!flag)   //如果!flag是为假则线程等待
			try {
				this.wait();
			}catch(Exception e) {
				
			}
		System.out.println(Thread.currentThread().getName()+"--消费者--"+this.name);
			
		flag = false;  //输出完资源之后把flag改为fale
		this.notifyAll(); 
		
	}
	
}

class Input implements Runnable {
	
	private Resource r;  //定义一个引用r
	
	Input(Resource r) {
		this.r = r;
	}
	
	public void run() {
		
		while(true) {
			r.set("啤酒");
		}
		
	}
	
}

class Output implements Runnable {
	
	private Resource r;
	
	Output(Resource r) {
		this.r = r;
	}
	
	public void run() {
		
		while(true) {
			
			r.out();
		}
		
	}
	
}

class TestWork {
	
	public static void main(String[] args) {
		
		Resource r = new Resource(); //创建资源对象
		
		Input in = new Input(r);  //资源对象作为参数,传入
		Output out = new Output(r);
		
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(in);
		Thread t3 = new Thread(out);
		Thread t4 = new Thread(out);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
	
}

JDK1.5新特性

JDK1.5 中提供了多线程升级解决方案:
Lock接口:替代了同步代码块或者同步函数
                     lock():获取锁
                     unlock():释放锁,为了防止异常出现,导致锁无法关闭,所以锁的关闭动作要放在finally中
Condition接口:出现替代了Object中的wait、notify、notifyAll方法。将这些解释器方法单独进行了封装,变成Condition监视器对象,可以任意锁进行组合。
                     await()对应wait()
                     singal()对应notify()
                     singalAll()对应notifyAll()
import java.util.concurrent.locks.*;

class Resource {
	
	private String name;
	private int count;
	private boolean flag = false;  //定义一个标记用来判断线程是否要等待
	
	private Lock lock = new ReentrantLock();  //new一个对象,ReentrantLock()是Lock的子类
	private Condition con_in = lock.newCondition();  //创建Condition类对象,并且一个Lock可以对应多个condition对象
	private Condition con_ou = lock.newCondition();
	
	public  void set(String name) throws Exception {
		
		lock.lock();
		try {
			while(flag)  //如果flag为true则输入线程等待
				con_in.await();
			
			this.name = name+count++;
			System.out.println(Thread.currentThread().getName()+"--生产者--"+this.name);
		
			flag = true;  //当线程输入了资源后,把标记改为true让输出线程输出资源
			
			con_ou.signal();
		}finally {
			lock.unlock();  //释放锁是必须要关闭的资源
			
		}
	}
	
	public  void out() throws Exception {
		lock.lock();
		try {
			while(!flag)   //如果!flag是为假则线程等待
				con_ou.await();
			System.out.println(Thread.currentThread().getName()+"--消费者--"+this.name);
			
			flag = false;  //输出完资源之后把flag改为fale
			con_in.signal(); //唤醒正在等待的输入线程。
		} finally {
			lock.unlock();
		}
		
	}
	
}

class Input implements Runnable {
	
	private Resource r;  //定义一个引用r
	
	Input(Resource r) {
		this.r = r;
	}
	
	public void run() {
		
		while(true) {
			try {
				r.set("啤酒");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	
}

class Output implements Runnable {
	
	private Resource r;
	
	Output(Resource r) {
		this.r = r;
	}
	
	public void run() {
		
		while(true) {
			
			try {
				r.out();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	
}

class TestWork {
	
	public static void main(String[] args) {
		
		Resource r = new Resource(); //创建资源对象
		
		Input in = new Input(r);  //资源对象作为参数,传入
		Output out = new Output(r);
		
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(in);
		Thread t3 = new Thread(out);
		Thread t4 = new Thread(out);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
	
}

停止线程

任务中都会有循环接口,控制住循环就可以结束任务,控制循环通常用定义标记来完成。stop方法已经过时,不再使用。
特殊情况:
当线程处于了冻结状态。
就不会读取到标记。那么线程就不会结束。当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。Thread类提供该方法 interrupt();
class StopThread implements Runnable {
	
	private boolean flag = true;
	
	public synchronized void run() {
		
		while(flag) {
			try { 
				wait();
			} catch(InterruptedException e) {
				System.out.println(Thread.currentThread().getName()+"exception");	
				
				flag = false;
			}
			
			System.out.println(Thread.currentThread().getName()+"正在运行");
			
		}
		
		
	}
	
	public void changeFlag()
	{
		flag = false;
	}
}

class StopThreadDemo {

	public static void main(String[] args) {
		
		StopThread st = new StopThread();
		
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(st);
		
		t1.setDaemon(true);
		t1.start();
		t2.start();
		
		int num = 0;
		
		while(true)
		{
			if(num++ == 60)
			{
				//st.changeFlag();
				t1.interrupt();
				t2.interrupt();
				break;
			}
			System.out.println(Thread.currentThread().getName()+"正在运行"+num);
		}
	}

}

线程类的其它方法

setDaemon():将调用此方法的线程标记为守护线程,该方法必须在启动线程前调用。
join():               等待调用此方法的线程结束
setPriority():   设置此线程的优先级可以加参数(MAX_PRIORITY)
toStirng():       返回该线程的字符串表现形式,包括线程名称,优先级,和线程组。
yield():             暂停当前正在执行的线程对象,并执行其他线程
class Demo implements Runnable {
	public void run() {
		for(int x=0; x<70; x++) {
			System.out.println(Thread.currentThread().toString()+"....."+x);
			Thread.yield();
		}
	}
}


class  JoinDemo
{
	public static void main(String[] args) throws Exception {
		Demo d = new Demo();
		Thread t1 = new Thread(d);
		Thread t2 = new Thread(d);
		t1.start();
		
		//t1.setPriority(Thread.MAX_PRIORITY); //将t1的优先级提高的最大

		t2.start();

		//t1.join();  //如果在这里调用了join()方法,则main线程会停下来 

		for(int x=0; x<80; x++) {
			//System.out.println("main....."+x);
		}
		System.out.println("over");
	}
}

























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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值