在接触Android时候发现java基础没打好,所以回来重新打基础
java线程基础
java线程是在一个程序代码中CPU同步运行多个程序片段,而不是一行代码一行代码地执行到底,这样做是为了在运行大程序时提高程序的运行效率。虽然说的是同步运行,其实是“微观串行,宏观并行”,只是线程之间的切换时间太短以至于我们看上去是并行的。另外线程的调度模式有 (1)分时模型 (2)抢占模型 java用的是抢占模型,其他知识以后再补充,现在放代码
重要提示:以下的代码的运行结果可能并不能代表多线程真正的运行顺序,因为本身线程运行时输出信号到显示器这段时间也是不可预计的,所以显示器上的显示顺序不完全代表运行代码时间先后。这个问题叫做显示调度器不可预测
1. 继承Thread
类,重写run
函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class ThreadTest { public static void main (String[] args) { MyThread thread1 = new MyThread ("thread1" ); MyThread thread2 = new MyThread ("thread2" ); thread1.start(); thread2.start(); System.out.println("The main runnnig is stopped" ); } } class MyThread extends Thread { public MyThread (String str) { super (str); } public void run () { for (int i=0 ;i<3 ;i++){ System.out.println(getName() + "is running" ); try { sleep(100 ); } catch (InterruptedException e) {} } System.out.println(getName() + "stopped" ); } }
运行结果如下 1 2 3 4 5 6 7 8 9 The main runnnig is stopped thread2is running thread1is running thread1is running thread2is running thread1is running thread2is running thread2stopped thread1stopped
2. 实现Runable
接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class TestSync implements Runnable { private int balance; @Override public void run () { for (int i = 0 ; i < 50 ; i++) { increament(); System.out.println("balance is " + balance); } } private void increament () { int i = balance; balance = i + 1 ; } } public class TestSyncTest { public static void main (String[] args) { TestSync job = new TestSync (); Thread a = new Thread (job); Thread b = new Thread (job); a.start(); b.start(); } }
线程调度函数及代码实例
sleep(long millis)
: 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
join()
: 在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class MyThread extends Thread { public MyThread (String name) { super (name); } public void run () { int result = 0 ; System.out.println(this .getName() + "thread is started!" ); for (int i = 0 ; i < 50 ; i++ ) { result += i; } System.out.println(this .getName() + "thread is stopped!" ); } } public class ThreadTest { public static void main (String[] args) throws InterruptedException { System.out.println("Main thread is started!" ); MyThread a = new MyThread ("A" ); a.start(); a.join(); System.out.println("Main thread is stopped!" ); } }
输出结果:1 2 3 4 Main thread is started! Athread is started! Athread is stopped! Main thread is stopped!
yield()
: 运行
–>可运行
,让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class MyThread extends Thread { public void run () { for (int i=0 ; i<5 ; i++) System.out.println(Thread.currentThread().getName() + " in control" ); } } public class ThreadTest { public static void main (String[]args) { MyThread t = new MyThread (); t.start(); for (int i=0 ; i<5 ; i++) { Thread.yield (); System.out.println(Thread.currentThread().getName() + " in control" ); } } }
可能的情况:
main运行时让掉CPU,过后main抢到CPU继续执行
main运行时让掉CPU,过后子线程抢到CPU继续执行
所以输出可能是1 2 3 4 5 6 7 8 9 10 Thread-0 in control main in control main in control main in control main in control main in control Thread-0 in control Thread-0 in control Thread-0 in control Thread-0 in control
也可能是1 2 3 4 5 6 7 8 9 10 Thread-0 in control Thread-0 in control Thread-0 in control Thread-0 in control Thread-0 in control main in control main in control main in control main in control main in control
生产者消费者 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 import java.util.LinkedList;import java.util.Queue;import java.util.Random;public class ProducerCustomer { public static void main (String args[]) { System.out.println("Solving Producer Consumper Problem" ); Queue<Integer> buffer = new LinkedList <>(); int maxSize = 10 ; Thread producer = new Producer (buffer, maxSize, "PRODUCER" ); Thread consumer = new Consumer (buffer, maxSize, "CONSUMER" ); producer.start(); consumer.start(); } } class Producer extends Thread { private Queue<Integer> queue; private int maxSize; public Producer (Queue<Integer> queue, int maxSize, String name) { super (name); this .queue = queue; this .maxSize = maxSize; } @Override public void run () { while (true ) { synchronized (queue) { while (queue.size() == maxSize) { try { System.out .println("Queue is full, " + "Producer thread waiting for " + "consumer to take something from queue" ); queue.wait(); } catch (Exception ex) { ex.printStackTrace(); } } Random random = new Random (); int i = random.nextInt(); System.out.println("Producing value : " + i); queue.add(i); queue.notifyAll(); } } } } class Consumer extends Thread { private Queue<Integer> queue; private int maxSize; public Consumer (Queue<Integer> queue, int maxSize, String name) { super (name); this .queue = queue; this .maxSize = maxSize; } @Override public void run () { while (true ) { synchronized (queue) { while (queue.isEmpty()) { System.out.println("Queue is empty," + "Consumer thread is waiting" + " for producer thread to put something in queue" ); try { queue.wait(); } catch (Exception ex) { ex.printStackTrace(); } } System.out.println("Consuming value : " + queue.remove()); queue.notifyAll(); } } } }
ABC交替打印 synchronized方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public class ABC_Synch { public static class ThreadPrinter implements Runnable { private String name; private Object prev; private Object self; private ThreadPrinter (String name, Object prev, Object self) { this .name = name; this .prev = prev; this .self = self; } @Override public void run () { int count = 10 ; while (count > 0 ) { synchronized (prev) { synchronized (self) { System.out.print(name); count--; self.notifyAll(); } try { if (count == 0 ) { prev.notifyAll(); } else { prev.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } } } } public static void main (String[] args) throws Exception { Object a = new Object (); Object b = new Object (); Object c = new Object (); ThreadPrinter pa = new ThreadPrinter ("A" , c, a); ThreadPrinter pb = new ThreadPrinter ("B" , a, b); ThreadPrinter pc = new ThreadPrinter ("C" , b, c); new Thread (pa).start(); Thread.sleep(10 ); new Thread (pb).start(); Thread.sleep(10 ); new Thread (pc).start(); Thread.sleep(10 ); } }
由交替打印代码可以得出wait()
和notify()
的区别
wait() 与 notify/notifyAll() 是Object类的方法,在执行两个方法时,要先获得锁。
当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态。
当执行notify/notifyAll方法时,会唤醒一个处于等待该 对象锁 的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁。
notify/notifyAll()
执行后,并不立即释放锁,而是要等到执行完临界区中代码后,再释放。
lock方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ABC_Lock { private static Lock lock = new ReentrantLock (); private static int state = 0 ; static class ThreadA extends Thread { @Override public void run () { for (int i = 0 ; i < 10 ; ) { try { lock.lock(); while (state % 3 == 0 ) { System.out.print("A" ); state++; i++; } } finally { lock.unlock(); } } } } static class ThreadB extends Thread { @Override public void run () { for (int i = 0 ; i < 10 ; ) { try { lock.lock(); while (state % 3 == 1 ) { System.out.print("B" ); state++; i++; } } finally { lock.unlock(); } } } } static class ThreadC extends Thread { @Override public void run () { for (int i = 0 ; i < 10 ; ) { try { lock.lock(); while (state % 3 == 2 ) { System.out.print("C" ); state++; i++; } } finally { lock.unlock(); } } } } public static void main (String[] args) { new ThreadA ().start(); new ThreadB ().start(); new ThreadC ().start(); } }
synchronized 和 lock的区别
synchronized
: 在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。
lock(ReentrantLock)
: 提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。
我们写同步的时候,优先考虑synchronized,如果有特殊需要,再进一步优化。ReentrantLock如果用的不好,不仅不能提高性能,还可能带来灾难。