多线程优点:我们电脑可以同时操作不同的软件,边听着歌,敲着代码,查看 pdf 文档,浏览网页等,CPU 在这些任务之间不停的切换,切换非常快,所以我们就觉得他们是在同时运行的。
使用多线程
继承 Thread 类
JDK 源码注释(Thread.java)如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
One is to declare a class to be a subclass(子类) of <code>Thread</code>. This subclass should override the <code>run</code> method of class <code>Thread</code>. An instance of the subclass can then be allocated and started. For example, a thread that computes primes larger than a stated value could be written as follows: //继承 Thread 类 class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; }
publicvoidrun(){ // compute primes larger than minPrime 重写 Thread 类的 run 方法 } }
The following code would then create a thread and start it running: //开启线程 PrimeThread p = new PrimeThread(143); p.start();
实现 Runnable 接口
JDK 源码注释(Thread.java)如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
The other way to create a thread is to declare a classthatimplementsthe <code>Runnable</code> interface. Thatclassthenimplementsthe <code>run</code> method. Aninstanceoftheclasscanthenbeallocated, passedasanargumentwhencreating <code>Thread</code>, and started. The same example in this other style looks like the following: //实现 Runnable 接口 classPrimeRunimplementsRunnable{ long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; }
publicvoidrun(){ // compute primes larger than minPrime //重写 run 方法 } }
The following code would then create a thread and start it running: //开启线程 PrimeRun p = new PrimeRun(143); new Thread(p).start();
//测试线程是否已经中断了,线程的状态不会受这个方法的影响 //线程中断被忽略,因为线程处于中断下不处于活动状态的线程由此返回false的方法反映出来 publicbooleanisInterrupted(){ return isInterrupted(false); } /** * Tests if some Thread has been interrupted. The interrupted state * is reset or not based on the value of ClearInterrupted that is * passed. */ privatenativebooleanisInterrupted(boolean ClearInterrupted);
run start main end run catchfalse java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.zhisheng.thread.thread1.MyThread2.run(MyThread2.java:12)
run start run catchfalse java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.zhisheng.thread.thread1.MyThread3.run(MyThread3.java:12)
/** * A hint to the scheduler that the current thread is willing to yield * its current use of a processor. The scheduler is free to ignore this * hint. * * <p> Yield is a heuristic attempt to improve relative progression * between threads that would otherwise over-utilise a CPU. Its use * should be combined with detailed profiling and benchmarking to * ensure that it actually has the desired effect. * * <p> It is rarely appropriate to use this method. It may be useful * for debugging or testing purposes, where it may help to reproduce * bugs due to race conditions. It may also be useful when designing * concurrency control constructs such as the ones in the * {@link java.util.concurrent.locks} package. */ //暂停当前正在执行的线程对象,并执行其他线程。暂停的时间不确定。 publicstaticnativevoidyield();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
publicclassMyThread5extendsThread { @Override publicvoidrun(){ double start = System.currentTimeMillis(); for (int i = 0; i < 200000; i++) { //yield();//暂停的时间不确定 i++; } double end = System.currentTimeMillis(); System.out.println("time is "+(end - start)); } publicstaticvoidmain(String[] args){ MyThread5 t5 = new MyThread5(); t5.start(); } }
/** * Marks this thread as either a {@linkplain #isDaemon daemon} thread * or a user thread. The Java Virtual Machine exits when the only * threads running are all daemon threads. * * <p> This method must be invoked before the thread is started. * * @param on * if {@code true}, marks this thread as a daemon thread * @throws IllegalThreadStateException * if this thread is {@linkplain #isAlive alive} * @throws SecurityException * if {@link #checkAccess} determines that the current * thread cannot modify this thread */ publicfinalvoidsetDaemon(boolean on){ checkAccess(); if (isAlive()) { thrownew IllegalThreadStateException(); } daemon = on; }
/** * Created by 10412 on 2017/6/3. * 消费者线程 */ publicclassResumeThreadextendsThread { private Resume r;
publicResumeThread(Resume r){ this.r = r; }
@Override publicvoidrun(){ while (true) { r.getValue(); } } }
主函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
package com.zhisheng.thread.thread5;
/** * Created by 10412 on 2017/6/3. * 一个生产者一个消费者测试 */ publicclassTest { publicstaticvoidmain(String[] args){ String str = new String(""); Product p = new Product(str); Resume r = new Resume(str);; ProductThread pt = new ProductThread(p); ResumeThread rt = new ResumeThread(r); pt.start(); rt.start(); } }
/** * Created by 10412 on 2017/6/3. */ publicclassTest { publicstaticvoidmain(String[] args){ DBTools dbTools = new DBTools(); for (int i = 0; i < 20; i++) { ThreadB tb = new ThreadB(dbTools); tb.start(); ThreadA ta = new ThreadA(dbTools); ta.start(); } } }
/** * 等待该线程终止的时间最长为 millis 毫秒。超时为 0 意味着要一直等下去。 * Waits at most {@code millis} milliseconds for this thread to * die. A timeout of {@code 0} means to wait forever. * * <p> This implementation uses a loop of {@code this.wait} calls * conditioned on {@code this.isAlive}. As a thread terminates the * {@code this.notifyAll} method is invoked. It is recommended that * applications not use {@code wait}, {@code notify}, or * {@code notifyAll} on {@code Thread} instances. * * @param millis * the time to wait in milliseconds * * @throws IllegalArgumentException * if the value of {@code millis} is negative * * @throws InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when this exception is thrown. */ publicfinalsynchronizedvoidjoin(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { thrownew 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; } } }
类 ThreadLocal 的使用
该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
get() 方法
1 2 3 4 5 6 7 8 9 10 11 12 13
public T get(){ Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
假定有一个绑定的缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition 实例来做到这一点。
classBoundedBuffer{ final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100]; int putptr, takeptr, count;
/** * Created by 10412 on 2017/6/4. */ publicclassTest { publicstaticvoidmain(String[] args)throws InterruptedException { MyService service = new MyService(); ThreadA ta = new ThreadA(service); ta.start(); Thread.sleep(5000); service.signal(); } }
@Override publicvoidrun(){ for (int i = 0; i < Integer.MAX_VALUE; i++) { service.getValue(); } } }
Test.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
package com.zhisheng.thread.thread10;
/** * Created by 10412 on 2017/6/4. */ publicclassTest { publicstaticvoidmain(String[] args){ MyService service = new MyService(); ThreadA ta = new ThreadA(service); ThreadB tb = new ThreadB(service); ta.start(); tb.start(); } }
/** * Created by 10412 on 2017/6/4. */ publicclassTest { publicstaticvoidmain(String[] args)throws InterruptedException { MyService service = new MyService(); ThreadA ta = new ThreadA(service); ta.setName("A"); ta.start(); Thread.sleep(1000); ThreadB tb = new ThreadB(service); tb.setName("B"); tb.start(); } }
运行结果:
1 2
A Read AAA 1496556770402 B write BBB 1496556780402
/** * Created by 10412 on 2017/6/4. */ publicclassMyObject { privatestatic MyObject instance = null; privateMyObject(){ } static { instance = new MyObject(); } publicstatic MyObject getInstance(){ return instance; } }
ThreadA.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14
package com.zhisheng.thread.thread16;
/** * Created by 10412 on 2017/6/4. */ publicclassThreadAextendsThread { @Override publicvoidrun(){ for (int i = 0; i < 5; i++) { System.out.println(MyObject.getInstance().hashCode()); } } }
Test.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
package com.zhisheng.thread.thread16;
/** * Created by 10412 on 2017/6/4. */ publicclassTest { publicstaticvoidmain(String[] args){ ThreadA ta1 = new ThreadA(); ThreadA ta2 = new ThreadA(); ThreadA ta3 = new ThreadA(); ta1.start(); ta2.start(); ta3.start(); } }