本文共 9247 字,大约阅读时间需要 30 分钟。
线程相关基本api使用
一、threadLocal
1、概念:是线程局部变量,不管哪个线程访问此变量,得到的值都是哪个线程当前的存储的值,每个线程有一个ThreadLocalMap , 它可以存此线程的变量,而如果把key值做成所有线程共享的静态变量或其他,这样就能以一个相同的key在不同的线程中存不同的对象。
2、使用:
public class T00_ThreadLocal { /**演示*/ public static void main(String args[]){ Thread t1 = new Thread(new Run1()); Thread t2 = new Thread(new Run2()); t1.start(); t2.start(); }}class TcUtil{ private static ThreadLocaltc = new ThreadLocal ();//泛型设置成什么,就能往ThreadLocalMap中设置什么值 public static ThreadLocal getTc() { return tc; }}/**线程1*/class Run1 implements Runnable{ @Override public void run() { TcUtil.getTc().set("我是线程1的值"); for (int i = 0; i < 5; i++) { try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} System.out.println("线程1倒计时"+(5-i)+"秒"); } System.out.println("拿线程1的值:"+TcUtil.getTc().get()); }}/**线程2*/class Run2 implements Runnable{ @Override public void run() { TcUtil.getTc().set("我是线程2的值"); for (int i = 0; i < 5; i++) { try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} System.out.println("线程2倒计时"+(5-i)+"秒"); } System.out.println("拿线程2的值:"+TcUtil.getTc().get()); }}
二、创建线程的方式:
概述:创建线程的方式
* 1、继承thread,重写run()方法,调用thread.start()开启线程 * 2、实现Runable,实现run()方法,调用thread.start()开启线程 * 3、实现Callable,实现call()方法,实际上是给Task的run调用。public class T01_CreateThread { public static void main(String[] args) throws ExecutionException, InterruptedException { // 方式一:Runnable Thread t1 = new Thread(new Runnable() { @Override public void run() { System.out.println("Runnable版"); } }); t1.start(); Thread t2 = new Thread(() -> { System.out.println("RunnableJDK8版"); }); t2.start(); // 方式二:继承Thread Thread t3 = new Thread() { public void run() { System.out.println("Thread版"); } }; t3.start(); // 方式三、实现Callable FutureTaskfutureTask = new FutureTask (new Callable () { @Override public Integer call() throws Exception { Thread.sleep(2000); return 1; } }); Thread thread = new Thread(futureTask); thread.start(); Integer result = futureTask.get(); System.out.println("这里是被阻塞的"); System.out.println("futureTask的执行结果" + result); } }
三、线程方法join、sleep、yield
* 概述:sleep可以释放当前cup资源多少时间,去干其他活。
* yield也是释放当前cup资源,但是放弃的时间不确定。 * join-在main线程调用thead.join,那么main线程会等待thead线程执行完才返回。public class T02_sleep_join_yield { public static void main(String[] args) throws InterruptedException { // 1、sleep停顿1000毫秒 Thread.sleep(1000); Thread t1 = new Thread("线程1"){ public void run(){ System.out.println("线程1开始了"); try { sleep(1800);} catch (InterruptedException e) { e.printStackTrace();} System.out.println("线程1执行完了"); } }; t1.start(); // 2、join主线程2000毫秒 t1.join(2000); // 这里注意,因为thread线程干活需要1800,如果join时间少于这个数值,那么主线程会提前结束。 System.out.println("主线程结尾!"); System.out.println("演示yield,实际上这里没演示出什么效果!!"); Thread t2 = new Thread("线程2"){ public void run(){ for (int i = 0; i < Integer.MAX_VALUE; i++) { System.out.println("线程2执行,值:"+i); mySleep(1); } } }; Thread t3 = new Thread("线程3"){ public void run(){ for (int i = 0; i < Integer.MAX_VALUE; i++) { System.out.println("线程3执行,值:"+i); mySleep(1); if(i%10==0) { yield(); } } } }; t2.start();t3.start(); t2.join(); t3.join(); } public static void mySleep(long millisecond) { long begin = System.currentTimeMillis(); while(true) { long end = System.currentTimeMillis(); if(end - begin > millisecond) { break; } } } }
四、synchronized
概述:synchronized关键字是用来加锁,使用在方法上或代码块中,如果加在实例方法上,那么锁就是此实例对象。如果加在静态方法上,那么锁就是类class对象。代码块中的锁为代码块中指定。
范例:
private static class Ticket extends Thread{ public Ticket(String name){ super(name); } private static volatile int ticket = 100; //一共有100张票,是静态类共享数据。 public void run(){ while(true){ synchronized (Ticket.class) { //同步的锁需要class,因为是此类多个对象的此值需要抢占此资源 if(ticket==0){ break; } System.out.println(getName()+"这是第"+ticket--+"张票"); } } } } public static void main(String[] args) { new Ticket("线程1").start(); new Ticket("线程2").start(); }
五、死锁演示:
概述:是由2个或2个以上线程由于资源竞争,处于互相等待的情况。
private static String lock1 = "锁1"; private static String lock2 = "锁2"; public static void main(String[] args){ new Thread(){ public void run() { while(true){ synchronized (lock1){ System.out.println(getName()+"获取:"+lock1+" 等锁:"+lock2); synchronized (lock2) { System.out.println(getName()+"获取"+lock2); } } } } }.start(); new Thread(){ public void run() { while(true){ synchronized (lock2){ System.out.println(getName()+"获取:"+lock2+" 等锁:"+lock1); synchronized (lock1) { System.out.println(getName()+"获取"+lock1); } } } } }.start(); }
六、Wait_Notify
概述:wait方法可以让当前线程放弃持有的锁,并且进入等待池,只有线程的方法调用notify或notifyAll时,
* 才可以把这些等待的对象重新竞争锁,而notify只能唤醒一个线程。注意:等待和唤醒必须是同一个锁。public static void main(String[] args) { Person p = new Person(); Produce produce = new Produce(p); Consume consume = new Consume(p); produce.start(); consume.start(); } private static class Person { private String name; private int age; private volatile boolean flag; // 标记用来判断当前是应该set还是get public synchronized void set(String name, int age) throws InterruptedException { if (flag) { this.wait(); } this.name = name; this.age = age; this.flag = false; this.notify(); } public synchronized void read() throws InterruptedException { if (!flag) { this.wait(); } System.out.println("name is:" + this.name + ":" + "age is:" + this.age); this.flag = false; this.notify(); } } private static class Produce extends Thread{ Person p; Produce(Person p) { this.p = p; } @Override public void run() { while (true) { try { p.set("zhangsan", 18); } catch (InterruptedException e) { e.printStackTrace(); } } } } private static class Consume extends Thread { Person p; Consume(Person p) { this.p = p; } @Override public void run() { while (true) { try { p.read(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
七、生成者消费者
public class T07_Produce { public static void main(String args[]){ // 仓库对象 Storage storage = new Storage(); // 生产者对象 Producer p1 = new Producer(storage); Producer p2 = new Producer(storage); Producer p3 = new Producer(storage); // 消费者对象 Consume c1 = new Consume(storage); Consume c2 = new Consume(storage); Consume c3 = new Consume(storage); // 设置生产者产品生产数量 p1.setNum(40); p2.setNum(23); p3.setNum(40); // 设置消费者产品消费数量 c1.setNum(50); c2.setNum(20); c3.setNum(30); // 线程开始执行 c1.start(); c2.start(); c3.start(); p1.start(); p2.start(); p3.start(); }}/** * 库存对象 */class Storage{ private final int MAX_SIZE = 100; private LinkedList
八、interrupt相关方法
* 概述:线程中断就是维护了一个线程的中断标记,没有中断就是false。
* 他们一共有三个方法: * 静态方法,Thread.interrupted(); // 判断当前线程是否中断,如果中断,清除中断,即中断标记变成false。 * 实例方法,thread.isInterrupted(); // 判断当前线程是否中断。中断标记不变。 * 实例方法,thread.interrupt(); // 设置为中断,中断标记为ture。* interrupt相关方法 * 概述:线程中断就是维护了一个线程的中断标记,没有中断就是false。 * 他们一共有三个方法: * 静态方法,Thread.interrupted(); // 判断当前线程是否中断,如果中断,清除中断,即中断标记变成false。 * 实例方法,thread.isInterrupted(); // 判断当前线程是否中断。中断标记不变。 * 实例方法,thread.interrupt(); // 设置为中断,中断标记为ture。 */public class T09_interrupt { public static void main(String[] args) throws InterruptedException { boolean interrupted = Thread.interrupted(); System.out.println(interrupted); // false boolean isInterrupted = Thread.currentThread().isInterrupted(); // 线程是否中断 System.out.println(isInterrupted); // false Thread.currentThread().interrupt(); // 设置成中断 isInterrupted = Thread.currentThread().isInterrupted(); // 线程是否中断 System.out.println(isInterrupted); // true interrupted = Thread.interrupted(); System.out.println(interrupted); // true isInterrupted = Thread.currentThread().isInterrupted(); // false System.out.println(isInterrupted); // false //实际案例!!! System.out.println("...................................."); Thread t1 = new Thread(new Server()); t1.start(); Thread.sleep(2000); t1.interrupt(); // 设置t1为中断,如果刚好sleep状态,需要catch块中进行处理。 } private static class Server implements Runnable { @Override public void run() { // 中断标记为false就一直运行 while(!Thread.currentThread().isInterrupted()){ try { Thread.sleep(200); } catch (InterruptedException e1) { // 如果外部调用interrupt(),而刚好sleep状态,那么此时中断标记变成false。 // 人工再变成true,才可以起到通过while循环中的判断停止线程的作用。 Thread.currentThread().interrupt(); } System.out.println(Thread.currentThread().getName()); } } }}
转载地址:http://ghuni.baihongyu.com/