l 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock
l Lock[是一个接口]
• void lock()
• void unlock()
l ReentrantLock[是Lock的一个实现子类]
package com.core.thread.demo14;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SellTicket implements Runnable {
private static int ticketNum = 100;
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock();//加锁
if (ticketNum > 0) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售"
+ ticketNum + "张票");
ticketNum--;
}
lock.unlock();//释放锁
}
}
}
package com.core.thread.demo14;
//某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票
//实现Runnable接口
public class Test {
public static void main(String[] args) {
SellTicket st = new SellTicket();
Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
package com.core.thread.demo15;
public class MyLock {
public static Object objA = new Object();
public static Object objB = new Object();
}
package com.core.thread.demo15;
public class DeadLock extends Thread{
private boolean flag;
public DeadLock(boolean flag){
this.flag = flag;
}
@Override
public void run() {
if(flag){
synchronized (MyLock.objA) {
System.out.println("if objA");
synchronized (MyLock.objB) {
System.out.println("if objB");
}
}
}else{
synchronized (MyLock.objB) {
System.out.println("else objB");
synchronized (MyLock.objA) {
System.out.println("else objA");
}
}
}
}
}
package com.core.thread.demo15;
public class Test {
public static void main(String[] args) {
Thread t1 = new DeadLock(true);
Thread t2 = new DeadLock(false);
t1.start();
t2.start();
}
}
l 通过设置线程(生产者)和获取线程(消费者)针对同一个学生对象进行操作
package com.core.thread.demo1;
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package com.core.thread.demo1;
public class GetThread implements Runnable {
private Student s;
public GetThread(Student s){
this.s = s;
}
@Override
public void run() {
System.out.println(s.getName()+"----"+s.getAge());
}
}
package com.core.thread.demo1;
public class SetThread implements Runnable {
private Student s;
public SetThread(Student s){
this.s = s;
}
@Override
public void run() {
s.setName("大黄");
s.setAge(20);
}
}
package com.core.thread.demo1;
public class Test {
public static void main(String[] args) {
Student s = new Student();
SetThread st = new SetThread(s);
GetThread gt = new GetThread(s);
Thread t1 = new Thread(st);
Thread t2 = new Thread(gt);
t2.start();
t1.start();
}
}
package com.core.thread.demo2;
public class SetThread implements Runnable {
private Student s;
private int x = 0;
public SetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
if (x % 2 == 0) {
s.setName("大黄");
s.setAge(20);
} else {
s.setName("小黑");
s.setAge(18);
}
x++;
}
}
}
package com.core.thread.demo2;
public class GetThread implements Runnable {
private Student s;
public GetThread(Student s){
this.s = s;
}
@Override
public void run() {
while(true){
System.out.println(s.getName()+"----"+s.getAge());
}
}
}
package com.core.thread.demo2;
public class SetThread implements Runnable {
private Student s;
private int x = 0;
public SetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
synchronized (s) {
if (x % 2 == 0) {
s.setName("大黄");
s.setAge(20);
} else {
s.setName("小黑");
s.setAge(18);
}
x++;
}
}
}
}
package com.core.thread.demo2;
public class GetThread implements Runnable {
private Student s;
public GetThread(Student s){
this.s = s;
}
@Override
public void run() {
while(true){
synchronized (s) {
System.out.println(s.getName()+"----"+s.getAge());
}
}
}
}
package com.core.thread.demo2;
public class Student {
public boolean flag = false;
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package com.core.thread.demo2;
public class SetThread implements Runnable {
private Student s;
private int x = 0;
public SetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
synchronized (s) {
if (s.flag) {// 如果有,则不用创建
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (x % 2 == 0) {
s.setName("大黄");
s.setAge(20);
} else {
s.setName("小黑");
s.setAge(18);
}
x++;
s.flag = true;// 修改标记
s.notify();// 唤醒
}
}
}
}
package com.core.thread.demo2;
public class GetThread implements Runnable {
private Student s;
public GetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
synchronized (s) {
if (!s.flag) {// 如果没有,则等待
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s.getName() + "----" + s.getAge());
s.flag = false;// 修改标记
s.notify();// 唤醒机制
}
}
}
}
package com.core.thread.demo2;
public class SetThread implements Runnable {
private Student s;
public SetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
synchronized (s) {
if (s.flag) {// 如果有,则不用创建
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
s.setName("大黄");
s.setAge(20);
System.out.println("生产一个");
s.flag = true;// 修改标记
s.notify();// 唤醒
}
}
}
}
package com.core.thread.demo2;
public class GetThread implements Runnable {
private Student s;
public GetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
synchronized (s) {
if (!s.flag) {// 如果没有,则等待
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费一个"+s.getName() + "----" + s.getAge());
s.flag = false;// 修改标记
s.notify();// 唤醒机制
}
}
}
}
l Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
• 默认情况下,所有的线程都属于主线程组。
• public final ThreadGroup getThreadGroup()
• 我们也可以给线程设置分组
• Thread(ThreadGroup group, Runnable target,String name)
package com.core.thread.demo4;
public class Test {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread t1 = new Thread(runnable, "线程1");
Thread t2 = new Thread(runnable, "线程2");
ThreadGroup tg1 = t1.getThreadGroup();
ThreadGroup tg2 = t2.getThreadGroup();
System.out.println(tg1.getName());// main,默认都属于主线程组
System.out.println(tg2.getName());// main
System.out.println("----------");
ThreadGroup newTG = new ThreadGroup("新开的一个线程组");
Thread tg11 = new Thread(newTG, runnable);
Thread tg22 = new Thread(newTG, runnable);
System.out.println(tg11.getThreadGroup().getName());// 新开的一个线程组
System.out.println(tg22.getThreadGroup().getName());// 新开的一个线程组
// 通过操作线程组可以操作里面的线程状态了。
}
}
package com.core.thread.demo5;
public class Student {
private String name;
private int age;
private boolean flag = false;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public synchronized void setStudent(String name, int age) {
if (flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setName(name);
setAge(age);
System.out.println("生产了一个");
this.flag = true;
this.notify();
}
public synchronized void getStudent() {
if (!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费了一个" + getName() + "---" + getAge());
this.flag = false;
this.notify();
}
}
package com.core.thread.demo5;
public class SetThread implements Runnable {
private Student s;
private int x = 0;
public SetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
s.setStudent("张三", 20);
}
}
}
package com.core.thread.demo5;
public class GetThread implements Runnable {
private Student s;
public GetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
s.getStudent();
}
}
}
package com.core.thread.demo5;
public class Test {
public static void main(String[] args) {
Student s = new Student();
SetThread st = new SetThread(s);
GetThread gt = new GetThread(s);
Thread t1 = new Thread(st);
Thread t2 = new Thread(gt);
t2.start();
t1.start();
}
}
l 程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。
• 线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
• 在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
l JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
• public static ExecutorService newCachedThreadPool()
• public static ExecutorService newFixedThreadPool(int nThreads)
• public static ExecutorService newSingleThreadExecutor()
• 这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
• Future> submit(Runnable task)
•
• 案例演示
• 创建线程池对象
• 创建Runnable实例
• 提交Runnable实例
• 关闭线程池
package com.core.thread.demo6;
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"---"+i);
}
}
}
package com.core.thread.demo6;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
//获得线程池
ExecutorService pool = Executors.newFixedThreadPool(3);
//可以执行Runnable或者Callable对象代表的线程
//Runnable对象
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//结束线程池
pool.shutdown();
}
}
package com.core.thread.demo7;
import java.util.concurrent.Callable;
public class MyCallable implements Callable {
@Override
public Object call() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"--"+i);
}
return null;
}
}
package com.core.thread.demo7;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
//创建线程池
ExecutorService pool = Executors.newFixedThreadPool(3);
pool.submit(new MyCallable());
pool.submit(new MyCallable());
//结束线程池
pool.shutdown();
}
}
package com.core.thread.demo7;
import java.util.concurrent.Callable;
public class MyCallable implements Callable {
private int num;
private int sum;
public MyCallable(int num) {
this.num = num;
}
@Override
public Integer call() throws Exception {
for (int i = 0; i <= num; i++) {
sum += i;
}
return sum;
}
}
package com.core.thread.demo7;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Test {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//创建线程池
ExecutorService pool = Executors.newFixedThreadPool(2);
Future f1 = pool.submit(new MyCallable(100));
Future f2 = pool.submit(new MyCallable(200));
Integer i1 = f1.get();
Integer i2 = f2.get();
System.out.println("i1 =" +i1);
System.out.println("i2 =" +i2);
//关闭线程
pool.shutdown();
}
}
package com.core.thread.demo9;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
// 匿名内部类
public static void main(String[] args) {
// 1. 继承Thread的方法
new Thread() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("继承Thread的方法" + i);
}
}
}.start();;
// 2. 实现Runnable接口方法
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("实现Runnable接口方法" + i);
}
}
}).start();
// 3. Callable方法
ExecutorService pool = Executors.newFixedThreadPool(1);
pool.submit(new Callable() {
@Override
public Object call() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println("Callable方法" + i);
}
return null;
}
});
//结束线程池
pool.shutdown();
}
}
package com.core.thread.timer;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javax.management.timer.TimerMBean;
public class Test {
public static void main(String[] args) {
//创建一个定时器对象
// Timer t = new Timer();
// MyTimerTask task = new MyTimerTask();
// //3秒后执行
// System.out.println("开始"+new Date());
// t.schedule(task, 3000);
//注意上面的方法不能够自动取消任务
//下面通过参数传递,将定时器t传到TimerTask里面
Timer t = new Timer();
System.out.println("开始"+new Date());
t.schedule(new MyTimerTask2(t), 3000);
}
}
// 这是一个任务
class MyTimerTask extends TimerTask {
@Override
public void run() {
System.out.println("执行一项任务");
System.out.println("结束"+new Date());
}
}
class MyTimerTask2 extends TimerTask {
private Timer t;
public MyTimerTask2(Timer t){
this.t = t;
}
@Override
public void run() {
System.out.println("执行一项任务");
System.out.println("结束"+new Date());
t.cancel();
}
}
package com.core.thread.timer1;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javax.management.timer.TimerMBean;
public class Test {
public static void main(String[] args) {
Timer t = new Timer();
//3秒后第一次执行,以后每1秒执行一次
t.schedule(new MyTimerTask(),3000,1000);
}
}
class MyTimerTask extends TimerTask {
@Override
public void run() {
System.out.println("执行一项任务");
}
}
1:多线程有几种实现方案,分别是哪几种?
两种。
继承Thread类
实现Runnable接口
扩展一种:实现Callable接口。这个得和线程池结合。
2:同步有几种方式,分别是什么?
两种。
同步代码块
同步方法
3:启动一个线程是run()还是start()?它们的区别?
start();
run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用
start():启动线程,并由JVM自动调用run()方法
4:sleep()和wait()方法的区别
sleep():必须指时间;不释放锁。
wait():可以不指定时间,也可以指定时间;释放锁。
5:为什么wait(),notify(),notifyAll()等方法都定义在Object类中
因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。
而Object代码任意的对象,所以,定义在这里面。
6:线程的生命周期图
新建 -- 就绪 -- 运行 -- 死亡
新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡
建议:画图解释。