在家做兼职的正规网站平台,宁波网站建设怎么样,可做百度百科参考资料的网站,暴雪回归新建线程
新建线程很简单。只要使用new 关键字创建一个线程对象#xff0c;并且调用 start 方法启动线程。
Thread t new Thread();
t.start();注意#xff1a;run 方法不是用来启动线程。如果调用 run 方法它只会作为普通方法来执行#xff0c;而不会开启线程执行。 终止…新建线程
新建线程很简单。只要使用new 关键字创建一个线程对象并且调用 start 方法启动线程。
Thread t new Thread();
t.start();注意run 方法不是用来启动线程。如果调用 run 方法它只会作为普通方法来执行而不会开启线程执行。 终止线程
一般来说线程在执行完毕后就会结束无须手工关闭。但凡是都有例外。Thread 类提供了一个 stop 方法来终止线程。如果调用 stop 方法就可以立即将一个线程终止。
目前 stop 方法已经过期。因为 stop 方法太过于暴力它会把执行到一半的线程终止此时可能会引起数据不一致问题。
举例对象 User 有 id、name 两个属性。写线程总是把 id、name 写成相同的值。当写线程在写对象时读线程由于无法获得锁因此必须等待所以读线程是看不见一个写了一半的对象。此时写线程写完id后很不辛被 stop此时对象 u 的 id 为1而 name 任然为0出于不一致状态。而被终止的写线程简单地讲锁释放度线程获取到锁后读取数据于是读到了 id1 而 name0 。
public class StopThreadTest {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 User(int id, String name) {this.id id;this.name name;}public void setId(int id) {this.id id;}public void setName(String name) {this.name name;}public int getId() {return id;}public String getName() {return name;}Overridepublic String toString() {return User{ id id , name name \ };}}public static class ChangeObjectThread extends Thread {Overridepublic void run() {while (true) {synchronized (u) {int i (int) (System.currentTimeMillis() / 1000);u.setId(i);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}u.setName(String.valueOf(i));}}}}public static class ReadObjectThread extends Thread {Overridepublic void run() {while (true) {synchronized (u) {if (u.getId() ! Integer.valueOf(u.getName())) {System.out.println(u.toString());}}}}}public static void main(String[] args) {try {new ReadObjectThread().start();while (true) {ChangeObjectThread thread new ChangeObjectThread();thread.start();Thread.sleep(150);thread.stop();}} catch (InterruptedException e) {e.printStackTrace();}}
}打印结果
User{id1619771639, name1619771638}
User{id1619771640, name1619771639}那么如果优雅的停止一个线程又不会产生数据不一致问题可以考虑定义一个开关通过开关去控制。
public class StopThreadTest {public static User u new User();public static boolean stopme true;public static class User {private int id;private String name;public User() {this.id 0;this.name 0;}public User(int id, String name) {this.id id;this.name name;}public void setId(int id) {this.id id;}public void setName(String name) {this.name name;}public int getId() {return id;}public String getName() {return name;}Overridepublic String toString() {return User{ id id , name name \ };}}public static void stopMe(){stopme false;}public static class ChangeObjectThread extends Thread {Overridepublic void run() {while (stopme) {synchronized (u) {int i (int) (System.currentTimeMillis() / 1000);u.setId(i);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}u.setName(String.valueOf(i));}}}}public static class ReadObjectThread extends Thread {Overridepublic void run() {while (true) {synchronized (u) {if (u.getId() Integer.valueOf(u.getName())) {System.out.println(u.toString());}System.out.println(u.toString());}}}}public static void main(String[] args) {try {new ReadObjectThread().start();while (true) {ChangeObjectThread thread new ChangeObjectThread();thread.start();Thread.sleep(150);stopMe();}} catch (InterruptedException e) {e.printStackTrace();}}
}日志打印
User{id1619774686, name1619774686}
User{id1619774686, name1619774686}
User{id1619774686, name1619774686}线程中断
从表面上理解中断就是让目标线程停止执行的意思实际上并非如此。
严格来讲线程中断并不会是线程立即退出而是给线程发送一个通知告知目标线程有人希望你退出。至于目标线程是否退出由目标线程自己决定。
线程中断三个方法
// 中断线程
public void interrupt();
// 判断线程是否中断
public boolean isInterrupted();
// 判断线程是否中断并清楚当前中断状态
public static boolean interrupted();interrupt() 方法通知目标方法中断也就是设置中断标志位中断标志位表示当前线程已经被中断了isInterrupted() 判断当前线程是否有被中断interrupted() 也是用来判断当前线程是否被中断但同时会清除当前线程的中断标志位状态。 public void interruptTest1(){try {Thread t new Thread() {Overridepublic void run() {while (true) {Thread.yield();}}};t.start();Thread.sleep(2000);t.interrupt();} catch (InterruptedException e) {e.printStackTrace();}}线程t 虽然进行了中断但是并没有线程中断后处理的逻辑因此线程t 即使被中断但是这个中断不会发生任何左右。
优化线程中断就退出while public void interruptTest2() {try {Thread t new Thread() {Overridepublic void run() {while (true) {// 判断当前线程是否被中断 if (Thread.currentThread().isInterrupted()){System.out.println(Interrupted);break;}Thread.yield();}}};t.start();Thread.sleep(2000);t.interrupt();} catch (InterruptedException e) {e.printStackTrace();}}等待和通知
为了支持多线程之间的协作JDK 提供了两个非常重要的接口线程等待 wait() 和通知 notify()。注意这两个方法不是在 Thread 类中而是在 Object 类。这也意味着任何对象都能调用。
public final void wait() throws InterruptedException;
public final native void notify();当一个对象实例调用wait 方法后当前线程就会在这个对象上等待。比如线程A 中调用了obj.wait() 方法那么线程A 就会停止继续执行转为等待状态。当其他线程调用obj.notify() 方法为止结束等待状态。此时obj 对象就俨然成为多个线程之间的有效通讯手段。
扩展
面试题多线程之间的通讯方式
wait()、notify()同步 synchronizedwhile 轮训管道通信(PipedInputStream、PipedOutPutStream)
PS清楚有这么一个东西即可如何实现水平有限可自行查阅。有错请指教
wait()、notify() 工作过程如果一个线程调用了 object.wait() 方法那么它就会进入object 对象的等待队列。在这个队列中可能会有多个线程。当调用 object.notify() 被调用时它会从这个等待队列中随机选择一个线程并将它唤醒。同时 Object 对象还提供了另一个方法 notifyAll() 方法它和notify() 功能基本一致不同的是notifyAll 会唤醒这个队列中的所有等待的线程而不是随机选择一个。
强调调用wait() 方法必须在 snchronzied 语句中无论是wait()、notify() 都需要先获得锁当执行wait() 方法后会释放这个锁。这样做的目的是使得其他等待该锁的线程不至于无法正常执行。
public class WaitNotifyTest {final static Object object new Object();public static class T1 extends Thread {Overridepublic void run() {synchronized (object) {System.out.println(System.currentTimeMillis() : T1 start);try {System.out.println(System.currentTimeMillis() : T1 wait for object);object.wait();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(System.currentTimeMillis() : T1 end);}}}public static class T2 extends Thread {Overridepublic void run() {synchronized (object) {System.out.println(System.currentTimeMillis() : T2 start ! notify one thread);object.notify();System.out.println(System.currentTimeMillis() : T2 end);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) {T1 t1 new T1();T2 t2 new T2();t1.start();t2.start();}}如上两个线程 t1、t2。t1 执行 object.wait() 方法前获取object 对象锁。因此在执行 object.wait() 是它是持有 object 锁wait() 执行后t1 会进入等待并释放 object 的锁。t2 在执行 notify() 之前也会先获取 object 的对象锁。t1 在得到 notify() 通知后还是会先尝试重新获取 object 锁。上述运行日志打印
1620273470618: T1 start
1620273470618: T1 wait for object
1620273470618: T2 start ! notify one thread
1620273470618: T2 end
1620273472620: T1 end挂起和继续执行
挂起suspend 和继续执行resume 是一对相反的操作被挂起suspend 的线程必须要等到继续执行resume 操作后才能继续执行。目前 suspend()、resume() 已经过时不推荐使用。
使用 suspend() 挂起线程会导致线程被暂停同时并不会释放任何锁资源。此时其他线程想要访问被它暂用的锁时都会导致无法正常继续执行。直到对应的线程进行了resume() 操作被挂起的线程才能继续从而其他阻塞的线程才可以继续执行。严重的情况是它暂用的锁不会被释放因此可能会导致整个系统工作不正常。而且对于被挂起的线程从它的线程状态上看居然还是Runnable 严重影响对系统当前状态的判断。
public class SuspengResumeTest {public static Object object new Object();static ChangeObjectThread t1 new ChangeObjectThread(t1);static ChangeObjectThread t2 new ChangeObjectThread(t2);public static class ChangeObjectThread extends Thread{public ChangeObjectThread(String name) {super.setName(name);}Overridepublic void run() {synchronized (object) {System.out.println(System.currentTimeMillis() in getName());Thread.currentThread().suspend();System.out.println(System.currentTimeMillis() in getName());}}}public static void main(String[] args) {try {t1.start();Thread.sleep(1000);t2.start();t1.resume();t2.resume();t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}}
}结果打印
1620285481858 in t1
1620285482859 in t1
1620285482859 in t2通过日志发现他们都获取到了锁。但是线程不会退出而是是会挂起。虽然主函数已经调用了 resume() 但是由于事件先后顺序的缘故导致 t2 线程被永远挂起并且占用了对象锁。
优化 suspend()、resume()
public class SuspengResumeTest2 {public static Object object new Object();public static class ChangeObjectThread extends Thread {volatile boolean suspendme false;public void suspendsMe() {suspendme true;}public void resumeMe() {suspendme false;synchronized (this) {notify();}}Overridepublic void run() {while (true) {synchronized (this) {while (suspendme) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}}synchronized (object) {System.out.println(in ChangeObjectThread);}Thread.yield();}}}public static class ReadObjectThread extends Thread{Overridepublic void run() {while (true) {synchronized (object) {System.out.println(in ReadObjectThread);}Thread.yield();}}}public static void main(String[] args) {try {ChangeObjectThread t1 new ChangeObjectThread();ReadObjectThread t2 new ReadObjectThread();t1.start();t2.start();Thread.sleep(1000);t1.suspendsMe();System.out.println(suspend t1 2 sec);Thread.sleep(2000);System.out.println(resume t1);t1.resumeMe();} catch (InterruptedException e) {e.printStackTrace();}}}等待线程结束join 和谦让yield
很多时候一个线程的执行很可能需要依赖于另外一个或者多个线程执行完毕之后才能继续执行。比如日常工作需要产品先出需求文档然后召开需求评审紧接着进行软件开发。JDK 提供了 join() 来实现这个功能。
public final void join() throws InterruptedException;
public final synchronized void join(long millis) throws InterruptedException;第一个 join() 表示无限等待他会一致阻塞当前线程直到目标线程执行完毕。
第二个 join(long) 表示最大等待时间如果超过给定时间目标线程还在执行当前线程也会因为“等不及了”而继续往下执行。
public class JoinTest {public volatile static int num 1;public static class JoinThread extends Thread {Overridepublic void run() {for (; num 100000000; num) ;}}public static void main(String[] args) {try {JoinThread joinThread new JoinThread();joinThread.start();joinThread.join();System.out.println(num : num);} catch (InterruptedException e) {e.printStackTrace();}}}结果打印
num :100000000如果把 joinThread.join(); 注释掉查看日志 num :1 。
主函数在等待 joinThread 线程执行完毕再继续执行此时 num 为 100000000。
扩展
join() 的本质是让调用线程 wait() 在当前线程对象实例上。源码
public final void join() throws InterruptedException {join(0);
}public final synchronized void join(long millis) throws InterruptedException {long base System.currentTimeMillis();long now 0;if (millis 0) {throw new IllegalArgumentException(timeout value is negative);}if (millis 0) {while (isAlive()) {wait(0);}} else {while (isAlive()) {long delay millis - now;if (delay 0) {break;}wait(delay);now System.currentTimeMillis() - base;}}}可以看到它让调用线程在当前线程对象上进行等待。当线程执行完成后被等待的线程会在退出前调用 notifyAll() 通知所有的等待线程继续执行。因此不建议直接在 Thread 对象实例上使用类似于 wait()和notify() 等方法因为这有可能影响系统API的工作。
Thread 类中的另一个方法 yield()定义
public static native void yield();静态方法一大执行它会使得当前线程让出CPU。但是要注意让出CPU 并不表示当前线程不执行。当前线程在让出CPU 后还会进行CPU 资源的争夺能够再次被分配就不一定了。因此Thread.yield() 的调用就好像再说我已经完成了一些最重要的工作了可以休息一下了可以给其他线程一些工作机会