多线程开发之基本线程机制
Thread.yield():
对静态方法 Thread.yield() 的调用声明了当前线程已经完成了生命周期中最重要的部分,可以切换给其它线程来执行。该方法只是对线程调度器的一个建议,而且也只是建议具有相同优先级的其它线程可以运行。
/** * Thread.yield() * */ public class test1 implements Runnable{ private int index; private int id; test1(int index){ id = index; } @Override public void run() { while(true){ System.out.println("线程"+id+"执行中"); Thread.yield(); } } public static void main(String[] args) { for (int i = 0; i < 10; i++) { new Thread(new test1(i)).start(); } } }
Executor:
CachedThreadPool:为每个任务都创建一个线程
FixedThreadPool:限制线程的数量,每次需要线程的事件处理器,通过直接从线程池中获取线程,使用完将线程放回线程池,多有线程都会一致存于线程池,知道显示的执行shutdown()方法
SingleThreadExecutor:可以将其看成大小为1的FixedThreadPool
CachedThreadPool:
/** * Executor * CachedThreadPool:为每个任务都创建一个线程 * */ public class test2 implements Runnable{ private int id; test2(int id){ this.id = id; } @Override public void run() { System.out.println("线程"+id); } public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); for (int i = 0; i < 3; i++) { exec.execute(new test2(i)); } exec.shutdown(); } }
FixedThreadPool:
/** * Executor * FixedThreadPool:所有任务只能使用固定大小的线程; * */ public class test3 implements Runnable{ private int id; test3(int id){ this.id = id; } @Override public void run() { System.out.println("线程"+id); } public static void main(String[] args) { ExecutorService exec = Executors.newFixedThreadPool(3); for (int i = 0; i < 3; i++) { exec.execute(new test3(i)); } exec.shutdown(); } }
SingleThreadExecutor:
/** * Executor * FixedThreadPool:所有任务只能使用固定大小的线程; * */ public class test4 implements Runnable{ @Override public void run() { System.out.println("线程执行"); } public static void main(String[] args) { ExecutorService exec = Executors.newSingleThreadExecutor(); exec.execute(new test4()); exec.shutdown(); } }
三种方式的选择
CachedThreadPool在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程,因此它是合理的Executor的首选。只有当这种方式会引发问题时,我们才需要考虑切换到FixedThreadPool。
sleep()
Thread.sleep(millisec) 方法会休眠当前正在执行的线程,millisec 单位为毫秒。
sleep() 可能会抛出 InterruptedException,因为异常不能跨线程传播回 main() 中,因此必须在本地进行处理。线程中抛出的其它异常也同样需要在本地进行处理。
sleep()调用的时候回阻塞当前进程执行其他进程,可用 Interrupted()中断当前进程,进程阻塞的时候不会释放锁。
/** * sleep() * */ public class SleepTest implements Runnable{ private int id; SleepTest(int id){ this.id = id; } @Override public void run() { System.out.println("线程"+id+"before"); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程"+id+"after"); } public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); for (int i = 1; i <= 5; i++) { exec.execute(new SleepTest(i)); } exec.shutdown(); } }
优先级
可以在任意时刻使用setPriority()设置优先级,使用getPriority()读取现用线程的优先级
/** * priority * */ public class PriorityTest implements Runnable{ private int priority; private int id; public PriorityTest(int id,int priority){ this.priority = priority; this.id = id; } @Override public void run() { Thread.currentThread().setPriority(priority); System.out.println("线程"+id+"running"); } public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); for (int i = 1; i <= 3; i++) { exec.execute(new PriorityTest(i,Thread.MIN_PRIORITY)); } exec.execute(new PriorityTest(4,Thread.MAX_PRIORITY));//我们会发现线程4会比线程123先执行 exec.shutdown(); } }
后台线程 Daemon:
守护线程(后台线程)是程序运行时在后台提供服务的线程,不属于程序中不可或缺的部分。
当所有非守护线程结束时,程序也就终止,同时会杀死所有守护线程。
main() 属于非守护线程。
使用 setDaemon() 方法将一个线程设置为守护线程
/** * Daemon * */ public class Daemon implements Runnable{ private int id; public Daemon(int id){ this.id = id; } @Override public void run() { System.out.println("线程"+id+"running"); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 20; i++) { Thread daemon = new Thread(new Daemon(i)); daemon.setDaemon(true); daemon.start(); } /*20条线程并没有都运行完毕*/ TimeUnit.MILLISECONDS.sleep(1);//不加这条堵会儿主线程,主线程结束后所有后台线程都被结束,一条后台线程的输出结果都看不到 } }
共同学习共同成长,若有错误,欢迎指出