进程:系统进行资源分配和调度的基本单位,线程的容器;程序是指令、数据及其组织形式的描述,进程是程序的实体
线程:线程就是轻量级进程,是程序执行的最小单位。
使用多线程而不是多进程去并发程序的设计,是因为线程间的切换和调度的成本远远小于进程!!!!
Idea中全局查找一个类快捷键:ctrl + shift + n
/*
线程状态
*/
public enum State { NEW, //线程创建
RUNNABLE, //线程执行
BLOCKED, //如果线程在执行过程中遇到了synchronized同步块,就会进入到阻塞状态
TIMED_WAITING, //有时间限制的等待
WAITING, //无时间限制的等待
TERMINATED; //执行完成
}
两种方法:
继承Thread类
public class ThreadInitDemo { public static void main(String[] args) { class ThreadDemo extends Thread{ @Override public void run(){ for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "--------->" + i); } } } ThreadDemo thread = new ThreadDemo(); thread.start(); for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "--------->" + i); } } }
实现Runnable接口
public class ThreadRunnable implements Runnable { public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "--------->" + i); } } public static void main(String[] args) { new Thread(new ThreadRunnable()).start(); for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "--------->" + i); } } }
假如直接调用run方法会怎样?
public class ThreadInitDemo { public static void main(String[] args) { class ThreadDemo extends Thread{ @Override public void run(){ for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "--------->" + i); } } } ThreadDemo thread = new ThreadDemo();
/*
阿喆请注意!!!!!
*/ thread.run();
for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "--------->" + i); } } }
结果表明:
并没有开启新的线程,还是主线程执行的!
那么,看看start方法的源码吧:
1 public synchronized void start() { 2 /*标志该线程是否启动过,没有启动过才能执行接下来的动作*/ 3 if (threadStatus != 0) 4 throw new IllegalThreadStateException(); 5 group.add(this); //将该线程加入到线程组中 6 boolean started = false; 7 try { 8 start0(); //启动start0方法 9 started = true; //设置是否启动为true,是否与ThreadStatus重合,此处不懂 10 } finally { 11 try { 12 if (!started) { 13 group.threadStartFailed(this); 14 } 15 } catch (Throwable ignore) { 16 } 17 } 18 }
其中:
threadStatus:表示这个线程未被启动
group.add(this):将我们创建的线程加入到线程组中,可见线程组是用数组存储的!!
start0():是一个本地方法,涉及到底层。Java无法直接控制操作系统开辟一条线程,据说Start0()是用c++写的,存储在本地方法库中。c++调用操作系统开辟一条线程,执行我们的任务。
线程执行步骤:Thread.start():调用start0()方法,创建一条线程,执行run方法;所以我们直接调用run方法,并没有开辟新的线程。
Thread.stop():被舍弃了哦,说它太暴力了,强行终止,可以看到stop0(),估计直接调用底层,直接杀死咯;这样可能引起一些数据不一致问题。
因为:Thread.stop()方法在结束线程,会直接释放所有的锁,这样可能导致数据不一致。
代码含义:read线程一直在读;write线程一直在写,但是写了150ms之后就终止了;导致id和name不一致!
public class StopThreadUnsafe { public static User u = new User(); public static class User{ private int id; private String name; public User() { this.id = 0; this.name = "0"; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name=‘" + name + ‘\‘‘ + ‘}‘; } } public static class ChangeObjectThread extends Thread{ @Override public void run(){ while (true){ synchronized (u){ int v = (int)(System.currentTimeMillis()/1000); u.setId(v); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } u.setName(String.valueOf(v)); } Thread.yield(); } } } public static class ReadObjectThread extends Thread{ @Override public void run(){ while (true){ synchronized (u){ if (u.getId() != Integer.parseInt(u.getName())){ System.out.println(u.toString()); } } Thread.yield(); } } } public static void main(String[] args) throws InterruptedException { new ReadObjectThread().start(); while (true){ Thread t = new ChangeObjectThread(); t.start(); Thread.sleep(150); t.stop(); } } }
将上述代码修改正确:
修改上增加setStopMe()方法,看不懂自己敲一遍就懂咯,就是设置了一个标志位,当写线程stop后,标志为改变,因为写是死循环,所以会检测到标志位改变了,直接退出,并没有时间去修改u。
说句实话,修改main方法中的sleep长短,就还是不安全的。书上会个锤子,害。
但是标志位,是一个保证线程安全的一种方法
public static class ChangeObjectThread extends Thread{ volatile boolean stopMe = false; public void setStopMe(){ stopMe = true; } @Override public void run(){ while (true){ if (stopMe){ System.out.println("我被终结了!!!"); } synchronized (u){ int v = (int)(System.currentTimeMillis()/1000); u.setId(v); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } u.setName(String.valueOf(v)); } Thread.yield(); } } }
1 public static void main(String[] args) throws InterruptedException { 2 3 new ReadObjectThread().start(); 4 while (true){ 5 ChangeObjectThread t = new ChangeObjectThread(); 6 t.start(); 7 Thread.sleep(150); 8 t.stop(); 9 t.setStopMe(); 10 } 11 }
线程中断并不会使线程立即退出,而是给线程发送一个通知,告知目标线程,有人希望你退出了!以至于目标线程接收到通知后如何处理,则完全由目标线程自行决定。
public void Thread.interrupt() // 中断线程 实例方法!! public boolean Thread.isInterrupted() // 判断是否中断 实例方法!!! public static boolean Thread.interrupted() //判断是否被中断,并清除当前中断状态 类方法!!!
public class InterruptedDemo { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(){ @Override public void run(){ while (true){ if (this.isInterrupted()){ System.out.println("15"); break; } Thread.yield(); } } }; t1.start(); Thread.sleep(2000); t1.interrupt(); } }
谨记:调用interrupt()方法后!!!请记得手动的在线程中写中断处理的执行语句
判断后,就直接将中断标志清除掉了,不知道有什么用!!!
本地方法,会抛出InterruptedException异常
如果睡眠状态的线程被中断了,就抛出异常!InterruptedException不是运行时异常。
运行时异常????(待补充)
所有对象都会有的方法
public final void wait() throws InterruptedException; public final native void notify();
当一个对象实例上调用wait()方法后,当前线程就会在这个对象上等待。
例如:在线程A上,调用obj.wait()方法,那么线程A就会停止继续执行,转为等待状态。等到,线程A会一直等到其它线程调用obj.notify()方法位置。这时,object对象俨然成了多个线程之间的通信手段
谨记:wait和notify的方法只能放在同步代码块中使用
执行流程:
Thread.sleep()方法可是不会释放锁的哦
public final void join() throws InterruptedException //没有时间限制 public final synchronized void join(long millis) throws InterruptedException //有时间限制
一个线程的输入可能非常依赖于另外一个或者多个线程的输出,此时这个线程就需要等待依赖线程执行完毕,才能继续执行。
public static native void yield() //主动让出当前CPU
我已经完成了一些重要工作,我可以休息一下了,你们来工作吧。
Java高并发设计-------------Java并行程序基础------------2
原文:https://www.cnblogs.com/sicheng-li/p/13034406.html