目录
第一章:多线程
1.2 多线程实现
范例1-1:定义一个线程操作类。
class MyThread extends Thread { // 这就是一个多线程的操作类 private String name ; // 定义类中的属性 public MyThread(String name) { // 定义构造方法 this.name = name ; } @Override public void run() { // 覆写run()方法,作为线程的主操作方法 for (int x = 0 ; x < 200 ; x ++) { System.out.println(this.name + " --> " + x); } } } |
范例1-2:启动多线程。
public class TestDemo { // 主类 public static void main(String[] args) { MyThread mt1 = new MyThread("线程A") ; // 实例化多线程类对象 MyThread mt2 = new MyThread("线程B") ; // 实例化多线程类对象 MyThread mt3 = new MyThread("线程C") ; // 实例化多线程类对象 mt1.start(); // 启动多线程 mt2.start(); // 启动多线程 mt3.start(); // 启动多线程 } } |
范例1-3:start()方法的源代码。
public synchronized void start() { if (threadStatus != 0) throw new IllegalThreadStateException(); group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { } } } private native void start0(); |
范例1-4:使用Runnable实现多线程。
class MyThread implements Runnable { // 定义线程主体类 private String name; // 定义类中的属性 public MyThread(String name) { // 定义构造方法 this.name = name; } @Override public void run() { // 覆写run()方法 for (int x = 0; x < 200; x++) { System.out.println(this.name + " --> " + x); } } } |
范例1-5:利用Thread类启动多线程。
public class TestDemo { public static void main(String[] args) { MyThread mt1 = new MyThread("线程A") ; // 实例化多线程类对象 MyThread mt2 = new MyThread("线程B") ; // 实例化多线程类对象 MyThread mt3 = new MyThread("线程C") ; // 实例化多线程类对象 new Thread(mt1).start(); // 利用Thread启动多线程 new Thread(mt2).start(); // 利用Thread启动多线程 new Thread(mt3).start(); // 利用Thread启动多线程 } } |
范例1-6:使用Lamda表达式实现多线程。
public class TestDemo { public static void main(String[] args) { String name = "线程对象" ; new Thread(() -> { for (int x = 0; x < 200; x++) { System.out.println(name + " --> " + x); } }).start();; } } |
范例1-7:通过继承Thread类实现卖票程序。
package com.yootk.demo; class MyThread extends Thread { // 线程的主体类 private int ticket = 5; // 一共5张票 @Override public void run() { // 线程的主方法 for (int x = 0; x < 50; x++) { // 循环50次 if (this.ticket > 0) { System.out.println("卖票,ticket = " + this.ticket --); } } } } public class TestDemo { public static void main(String[] args) throws Exception { MyThread mt1 = new MyThread() ; // 创建线程对象 MyThread mt2 = new MyThread() ; // 创建线程对象 MyThread mt3 = new MyThread() ; // 创建线程对象 mt1.start() ; // 启动线程 mt2.start() ; // 启动线程 mt3.start() ; // 启动线程 } } |
范例1-8:利用Runnable接口来实现多线程。
package com.yootk.demo; class MyThread implements Runnable { // 线程的主体类 private int ticket = 5; // 一共5张票 @Override public void run() { // 线程的主方法 for (int x = 0; x < 50; x++) { // 循环50次 if (this.ticket > 0) { System.out.println("卖票,ticket = " + this.ticket --); } } } } public class TestDemo { public static void main(String[] args) throws Exception { MyThread mt = new MyThread(); // 创建线程对象 new Thread(mt).start() ; // 启动线程 new Thread(mt).start() ; // 启动线程 new Thread(mt).start() ; // 启动线程 } } |
范例1-9:使用Thread类实现数据共享的概念。
package com.yootk.demo; class MyThread extends Thread { // 线程的主体类 private int ticket = 5; // 一共5张票 @Override public void run() { // 线程的主方法 for (int x = 0; x < 50; x++) { // 循环50次 if (this.ticket > 0) { System.out.println("卖票,ticket = " + this.ticket --); } } } } public class TestDemo { public static void main(String[] args) throws Exception { MyThread mt = new MyThread(); // 创建线程对象 new Thread(mt).start() ; // 启动线程 new Thread(mt).start() ; // 启动线程 new Thread(mt).start() ; // 启动线程 } } |
范例1-10:定义一个线程主体类。
import java.util.concurrent.Callable; class MyThread implements Callable<String> { // 多线程主体类 private int ticket = 10; // 卖票 @Override public String call() throws Exception { for (int x = 0; x < 100; x++) { if (this.ticket > 0) { // 还有票可以出售 System.out.println("卖票,ticket = " + this.ticket--); } } return "票已卖光!"; // 返回结果 } } |
范例1-11:启动多线程。
public class TestDemo { public static void main(String[] args) throws Exception { MyThread mt1 = new MyThread(); // 实例化多线程对象 MyThread mt2 = new MyThread(); // 实例化多线程对象 FutureTask<String> task1 = new FutureTask<String>(mt1) ; FutureTask<String> task2 = new FutureTask<String>(mt2) ; // FutureTask是Runnable接口子类,所以可以使用Thread类的构造来接收task对象 new Thread(task1).start(); // 启动第一个线程 new Thread(task2).start(); // 启动第二个线程 // 多线程执行完毕后可以取得内容,依靠FutureTask的父接口Future中的get()方法实现 System.out.println("A线程的返回结果:" + task1.get()); System.out.println("B线程的返回结果:" + task2.get()); } } |
1.3 多线程常用操作方法
范例1-12:观察线程的命名。
package com.yootk.demo; class MyThread implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName()); } } public class TestDemo { public static void main(String[] args) throws Exception { MyThread mt = new MyThread(); new Thread(mt, "自己的线程A").start(); new Thread(mt).start(); new Thread(mt, "自己的线程B").start(); new Thread(mt).start(); new Thread(mt).start(); } } |
范例1-13:取得线程名字。
package com.yootk.demo; class MyThread implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName()); } } public class TestDemo { public static void main(String[] args) throws Exception { MyThread mt = new MyThread(); new Thread(mt, "自己的线程对象").start(); mt.run(); // 直接调用run()方法,main } } |
范例1-14:观察休眠特点。
package com.yootk.demo; class MyThread implements Runnable { @Override public void run() { for (int x = 0; x < 10000; x++) { try { Thread.sleep(1000); // 每次执行休眠1s } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ",x = " + x); } } } public class TestDemo { public static void main(String[] args) throws Exception { MyThread mt = new MyThread(); new Thread(mt, "自己的线程对象A").start(); } } |
范例1-15:设置线程优先级。
package com.yootk.demo; class MyThread implements Runnable { @Override public void run() { for (int x = 0; x < 20; x++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ",x = " + x); } } } public class TestDemo { public static void main(String[] args) throws Exception { MyThread mt = new MyThread(); Thread t1 = new Thread(mt, "自己的线程对象A"); Thread t2 = new Thread(mt, "自己的线程对象B"); Thread t3 = new Thread(mt, "自己的线程对象C"); T3.setPriority(Thread.MAX_PRIORITY); // 修改一个线程对象的优先级 t1.start(); t2.start(); t3.start(); } } |
范例1-16:主方法优先级。
public class TestDemo { public static void main(String[] args) throws Exception { System.out.println(Thread.currentThread().getPriority()); } } |
范例1-17:观察非同步情况下的操作。
package com.yootk.demo; class MyThread implements Runnable { private int ticket = 5; // 一共有5张票 @Override public void run() { for (int x = 0; x < 20; x++) { if (this.ticket > 0) { // 判断当前是否还有剩余票 try { Thread.sleep(100); // 休眠1s,模拟延迟 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 卖票,ticket = " + this.ticket--); } } } } public class TestDemo { public static void main(String[] args) throws Exception { MyThread mt = new MyThread(); new Thread(mt, "票贩子A").start(); // 启动多线程 new Thread(mt, "票贩子B").start(); // 启动多线程 new Thread(mt, "票贩子C").start(); // 启动多线程 new Thread(mt, "票贩子D").start(); // 启动多线程 } } |
范例1-18:观察同步块。
package com.yootk.demo; class MyThread implements Runnable { private int ticket = 5; // 一共有5张票 @Override public void run() { for (int x = 0; x < 20; x++) { synchronized(this) { // 定义同步代码块 if (this.ticket > 0) { // 判断当前是否还有剩余票 try { Thread.sleep(100); // 休眠1s,模拟延迟 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 卖票,ticket = " + this.ticket--); } } } } } public class TestDemo { public static void main(String[] args) throws Exception { MyThread mt = new MyThread(); new Thread(mt, "票贩子A").start(); // 启动多线程 new Thread(mt, "票贩子B").start(); // 启动多线程 new Thread(mt, "票贩子C").start(); // 启动多线程 new Thread(mt, "票贩子D").start(); // 启动多线程 } } |
范例1-19:使用同步方法解决问题。
package com.yootk.demo; class MyThread implements Runnable { private int ticket = 5; // 一共有5张票 @Override public void run() { for (int x = 0; x < 20; x++) { this.sale(); // 卖票操作 } } public synchronized void sale() { // 同步方法 if (this.ticket > 0) { // 判断当前是否还有剩余票 try { Thread.sleep(100); // 休眠1s,模拟延迟 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 卖票,ticket = " + this.ticket--); } } } public class TestDemo { public static void main(String[] args) throws Exception { MyThread mt = new MyThread(); new Thread(mt, "票贩子A").start(); // 启动多线程 new Thread(mt, "票贩子B").start(); // 启动多线程 new Thread(mt, "票贩子C").start(); // 启动多线程 new Thread(mt, "票贩子D").start(); // 启动多线程 } } |
范例1-20:程序死锁操作。
package com.yootk.demo; class A { public synchronized void say(B b) { System.out.println("A先生说:把你的本给我,我给你笔,否则不给!"); b.get(); } public synchronized void get() { System.out.println("A先生:得到了本,付出了笔,还是什么都干不了!"); } } class B { public synchronized void say(A a) { System.out.println("B先生说:把你的笔给我,我给你本,否则不给!"); a.get(); } public synchronized void get() { System.out.println("B先生:得到了笔,付出了本,还是什么都干不了!"); } } public class TestDemo implements Runnable { private static A a = new A(); // 定义类对象 private static B b = new B(); // 定义类对象 public static void main(String[] args) throws Exception { new TestDemo(); // 实例化本类对象 } public TestDemo() { // 构造方法 new Thread(this).start(); // 启动线程 b.say(a); // 互相引用 } @Override public void run() { a.say(b); // 互相引用 } } |
1.5 线程间的经典操作案例——生产者与消费者案例
范例1-21:程序基本模型。
package com.yootk.demo; class Message { private String title ; // 保存信息的标题 private String content ; // 保存信息的内容 public void setTitle(String title) { this.title = title; } public void setContent(String content) { this.content = content; } public String getTitle() { return title; } public String getContent() { return content; } } class Producer implements Runnable { // 定义生产者 private Message msg = null ; public Producer(Message msg) { this.msg = msg ; } @Override public void run() { for (int x = 0; x < 50; x++) { // 生产50次数据 if (x % 2 == 0) { this.msg.setTitle("李兴华") ; // 设置title属性 try { Thread.sleep(100) ; // 延迟操作 } catch (InterruptedException e) { e.printStackTrace(); } this.msg.setContent("Java讲师") ; // 设置content属性 } else { this.msg.setTitle("mldn") ; // 设置title属性 try { Thread.sleep(100) ; } catch (InterruptedException e) { e.printStackTrace(); } this.msg.setContent("www.mldnjava.cn") ; // 设置content属性 } } } } class Consumer implements Runnable { // 定义消费者 private Message msg = null ; public Consumer (Message msg) { this.msg = msg ; } @Override public void run() { for (int x = 0; x < 50; x++) { // 取走50次数据 try { Thread.sleep(100) ; // 延迟 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.msg.getTitle() + " --> " + this.msg.getContent()); } } } public class TestDemo { public static void main(String[] args) throws Exception { Message msg = new Message() ; // 定义Message对象,用于保存和取出数据 new Thread(new Producer(msg)).start() ; // 启动生产者线程 new Thread(new Consumer(msg)).start() ; // 取得消费者线程 } } |
范例1-22:加入同步,解决数据错乱问题。
package com.yootk.demo; class Message { private String title ; // 保存信息的标题 private String content ; // 保存信息的内容 public synchronized void set(String title, String content) { this.title = title; try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } this.content = content; } public synchronized void get() { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.title + " --> " + this.content); } // setter、getter略 } class Producer implements Runnable { // 定义生产者 private Message msg = null ; public Producer(Message msg) { this.msg = msg ; } @Override public void run() { for (int x = 0; x < 50; x++) { // 生产50次数据 if (x % 2 == 0) { this.msg.set("李兴华","Java讲师") ; // 设置属性 } else { this.msg.set("mldn","www.mldnjava.cn") ; // 设置属性 } } } } class Consumer implements Runnable { // 定义消费者 private Message msg = null ; public Consumer (Message msg) { this.msg = msg ; } @Override public void run() { for (int x = 0; x < 50; x++) { // 取走50次数据 this.msg.get() ; // 取得属性 } } } public class TestDemo { public static void main(String[] args) throws Exception { Message msg = new Message() ; // 定义Message对象,用于保存和取出数据 new Thread(new Producer(msg)).start() ; // 启动生产者线程 new Thread(new Consumer(msg)).start() ; // 取得消费者线程 } } |
范例1-23:解决程序问题。
class Message { private String title; private String content; private boolean flag = true; // flag == true:表示可以生产,但是不能取走 // flag == false:表示可以取走,但是不能生产 public synchronized void set(String title, String content) { if (this.flag == false) { // 已经生产过了,不能生产 try { super.wait(); // 等待 } catch (InterruptedException e) { e.printStackTrace(); } } this.title = title; try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } this.content = content; this.flag = false; // 已经生产完成,修改标志位 super.notify(); // 唤醒等待线程 } public synchronized void get() { if (this.flag == true) { // 未生产,不能取走 try { super.wait(); // 等待 } catch (InterruptedException e) { e.printStackTrace(); } } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.title + " --> " + this.content); this.flag = true; // 已经取走了,可以继续生产 super.notify(); // 唤醒等待线程 } // setter、getter略 } |
1.6 线程的生命周期
范例1-24:停止线程运行。
package com.yootk.demo; class MyThread implements Runnable { private boolean flag = true; // 定义标志位属性 public void run() { // 覆写run()方法 int i = 0; while (this.flag) { // 循环输出 while (true) { System.out.println(Thread.currentThread().getName() + "运行,i = " + (i++)); // 输出当前线程名称 } } } public void stop() { // 编写停止方法 this.flag = false; // 修改标志位 } } public class StopDemo { public static void main(String[] args) { MyThread my = new MyThread(); // 实例化Runnable接口对象 Thread t = new Thread(my, "线程"); // 建立线程对象 t.start() ; // 启动线程 my.stop() ; // 线程停止,修改标志位 } } |