线程的各个状态
-
新建状态(new):新创建了一个线程对象。
-
就绪状态 (Runnable): 该线程调用strat方法,等待获取CPU的使用权
-
运行状态 : 该线程正在使用cup
-
阻塞状态:阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。 -
死亡状态 : 即线程结束
多线程sleep方法
sleep () 方法顾名思义就是让该线程进行休眠状态
public class ThreadDemo implements Runnable{
public static void main(String[] args) {
new Thread(new ThreadDemo()).start();
for(int i = 0 ; i < 100 ; i ++) {
System.out.println("main"+i);
}
}
@Override
public void run() {
try {
Thread.sleep(1000); //睡眠一秒
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
}
注意:当sleep()时,不会释放锁
多线程join方法
join方法可以使当前线程进入等待状态
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
ThreadTest t1=new ThreadTest("A");
ThreadTest t2=new ThreadTest("B");
ThreadTest t3=new ThreadTest("C");
t1.start();
t2.start();
t3.start();
}
}
class ThreadTest extends Thread {
private String name;
public ThreadTest(String name){
this.name=name;
}
public void run(){
for(int i=1;i<=5;i++){
System.out.println(name+"-"+i);
}
}
}
没使用join方法线程交替
A-1
C-1
C-2
C-3
B-1
B-2
C-4
C-5
A-2
B-3
A-3
A-4
B-4
A-5
B-5
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
ThreadTest t1=new ThreadTest("A");
ThreadTest t2=new ThreadTest("B");
ThreadTest t3=new ThreadTest("C");
t1.start();
t2.start();
t1.join(); //
t3.start();
}
}
class ThreadTest extends Thread {
private String name;
public ThreadTest(String name){
this.name=name;
}
public void run(){
for(int i=1;i<=5;i++){
System.out.println(name+"-"+i);
}
}
}
A-1
B-1
A-2
B-2
A-3
B-3
A-4
B-4
A-5
B-5
C-1
C-2
C-3
C-4
C-5
join方法使得当前线程进入等待状态,这个程序中指的当前线程就是main线程,即使得main线程进入的等待状态,无法执行C.start方法。A,B线程交替运行完毕后,才会执行C.start()
守护线程
用户线程和守护线程
用户线程:也叫工作线程,线程的任务执行完或者通知方式结束
守护线程:一般是位工作线程服务的,当所有的用户线程技术,守护线程自动结束,使用Thread.setDaemon(true)方法, 线程变成守护线程 。
常见的守护线程:垃圾回收机制
public class ThreadDemo {
public static void main(String[] args) {
Thread t1 = new MyCommon();
Thread t2 = new Thread(new MyDaemon());
t2.setDaemon(true); // 设置为守护线程
t1.start();
t2.start();
}
}
class MyCommon extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("线程1第" + i + "次执行!");
try {
Thread.sleep(7);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyDaemon implements Runnable {
@Override
public void run() {
for (int i = 0; i < 9999; i++) {
System.out.println("守护线程" + i + "次执行!");
}
}
}
守护线程5235次执行!
守护线程5236次执行!
守护线程5237次执行!
守护线程5238次执行!
守护线程5239次执行!
守护线程5240次执行!
守护线程5241次执行!
守护线程5242次执行!
守护线程5243次执行!
守护线程5244次执行!
Process finished with exit code 0
守护线程执行到5244次,程序就结束了。
当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
多线程synchronized同步锁
关键字 synchronized可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块(主要是对方法或者代码块中存在共享数据的操作),保证线程安全。
多线程买票程序
public class ThreadDemo {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(ticket,"A").start();
new Thread(ticket,"B").start();
new Thread(ticket,"C").start();
}
}
class Ticket implements Runnable{
private int ticketNum = 10;
private boolean flag = true;
@Override
public void run() {
while (flag) {
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void buy() throws InterruptedException {
if(ticketNum <= 0 ) {
flag = false;
return ;
}
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+"买到" + ticketNum --);
}
}
可以看出程序出现了多买的不安全线程情况
解决方法:使用同步锁。
同步锁修饰的方法或对象,可以使的其,被线程调用时,只允许一个线程访问。就像厕所一样,同一时间只允许一个人访问,只有使用完下一个人才能访问。
public class ThreadDemo {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(ticket,"A").start();
new Thread(ticket,"B").start();
new Thread(ticket,"C").start();
}
}
class Ticket implements Runnable{
private int ticketNum = 1000;
private boolean flag = true;
@Override
public void run() {
while (flag) {
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//同步锁
private synchronized void buy() throws InterruptedException {
if(ticketNum <= 0 ) {
flag = false;
return ;
}
System.out.println(Thread.currentThread().getName()+"买到" + ticketNum --);
}
}