Java多线程

    技术2022-07-11  72

    线程就是程序执行的一条路径

    创建线程两种方式对比:

    继承Thread:可以直接使用Thread类中的方法,代码简单。但如果已经有了父类就不能使用这个方法(优先考虑)实现Runnable接口:有了父类也没有关系,父类也可以实现接口,而且接口可以多实现。但需要先获得Thread对象后,才能获得Thread方法,代码复杂

    两种方式源码对比:

    继承Thread:由于子类重写了Thread类的run()方法,当调用start()方法,直接找子类的run()方法实现Runnable接口:构造方法传入了Runnable的引用,成员变量记住了它,start()调用run()方法时内部判断成员变量Runnable的引用是否为空,不为空编译时看的是Runnable的run(),运行时执行的是子类的run()方法。 package day23; public class Dk1EstablishThread { //匿名内部类创建线程 public static void main(String[] args) { //1.继承Thread new Thread() { public void run() { //重写run()方法 for (int i = 0; i < 10; i++) { System.out.println("继承Thread"); } } }.start();; //2.实现Runnable接口 new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("实现Runnable接口"); } } }).start(); //两个线程交替执行 } }

    同步代码块:synchronized(锁){},任意对象都可以当作锁,匿名对象不行。

    同步方法:

    线程安全:Vector、StringBuffer、HashTable

    线程不安全:ArrayList、StringBuilder、HashMap

    Runtime类:

    package day25; public class Dk2Runtime { //Runtime单例设计模式 public static void main(String[] args) { Runtime r = Runtime.getRuntime(); //r.exec(dos命令); } }

    Timer类:

    sleep()和wait()方法区别:

    sleep()方法必须传入参数,参数就是时间,当时间到了自动唤醒

    wait()方法不是必须传入参数,如果没有参数遇到wait()就等待,如果传入参数,等参数的时间到了后等待

    sleep()方法在同步中不释放锁,因为它可以自己醒来

    wait()方法在同步中释放锁,因为它需要别人叫醒

    package day25; public class Dk3Wait { //三个线程之间互相通信jdk1.5版本之前 public static void main(String[] args) { // TODO Auto-generated method stub Printer p = new Printer(); new Thread() { public void run() { while (true) { try { p.print1(); } catch (Exception e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while (true) { try { p.print2(); } catch (Exception e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while (true) { try { p.print3(); } catch (Exception e) { e.printStackTrace(); } } } }.start(); } } class Printer { private int flag = 1; //定义标记 private Object obj = new Object(); public void print1() throws InterruptedException { synchronized (this) { while (flag != 1) { this.wait(); } System.out.print("J"); System.out.print("a"); System.out.print("v"); System.out.print("a"); System.out.println(); flag = 2; //this.notify(); //随机唤醒另一条线程 this.notifyAll(); //唤醒所有线程 } } public void print2() throws InterruptedException { synchronized (this) { while (flag != 2) { this.wait(); } System.out.print("P"); System.out.print("y"); System.out.print("t"); System.out.print("h"); System.out.print("o"); System.out.print("n"); System.out.println(); flag = 3; this.notifyAll(); } } public void print3() throws InterruptedException { synchronized (this) { while (flag != 3) { this.wait(); } System.out.print("C"); System.out.print("+"); System.out.print("+"); System.out.println(); flag = 1; this.notifyAll(); } } } package day25; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Dk4Lock { //互斥锁 public static void main(String[] args) { Printer2 p = new Printer2(); new Thread() { public void run() { while (true) { try { p.print1(); } catch (Exception e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while (true) { try { p.print2(); } catch (Exception e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while (true) { try { p.print3(); } catch (Exception e) { e.printStackTrace(); } } } }.start(); } } class Printer2 { private ReentrantLock r = new ReentrantLock(); private Condition c1 = r.newCondition(); private Condition c2 = r.newCondition(); private Condition c3 = r.newCondition(); private int flag = 1; //定义标记 private Object obj = new Object(); public void print1() throws InterruptedException { r.lock(); if (flag != 1) { c1.await(); //也可以调用wait() } System.out.print("J"); System.out.print("a"); System.out.print("v"); System.out.print("a"); System.out.println(); flag = 2; c2.signal(); r.unlock(); } public void print2() throws InterruptedException { r.lock(); if (flag != 2) { c2.await(); } System.out.print("P"); System.out.print("y"); System.out.print("t"); System.out.print("h"); System.out.print("o"); System.out.print("n"); System.out.println(); flag = 3; c3.signal(); r.unlock(); } public void print3() throws InterruptedException { r.lock(); if (flag != 3) { c3.await(); } System.out.print("C"); System.out.print("+"); System.out.print("+"); System.out.println(); flag = 1; c1.signal(); r.unlock(); } }

    线程组:如果没有给定线程属于哪个组,默认就属于主线程组

    package day25; public class MyRunner implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "..." + i); } } } package day25; public class Dk5ThreadGroup { //线程组 public static void main(String[] args) { MyRunner mr = new MyRunner(); ThreadGroup tg = new ThreadGroup("我是一个线程组"); Thread t1 = new Thread(tg,mr,"张三"); //将线程“张三”加入指定组 Thread t2 = new Thread(tg,mr,"李四"); System.out.println(tg.getName()); } } //输出 我是一个线程组

    线程池:程序启动一个新线程成本较高,使用线程池可以提高性能,尤其程序中创建大量生存期很短的线程时。线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。

    从jdk1.5开始内置线程池

    package day25; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Dk6ThreadPool { //线程池 public static void main(String[] args) { ExecutorService pool = Executors.newFixedThreadPool(2); //创建线程池,可以放两条线程 MyRunner mr1 = new MyRunner(); //创建Runnable的子类对象 MyRunner mr2 = new MyRunner(); pool.submit(mr1); pool.submit(mr2); pool.shutdown(); //关闭线程池,不接受新任务 } }

    Processed: 0.012, SQL: 9