多线程相关知识的课程安排:
1、Java中如何去实现多线程?
线程的生命周期:
new好了一个线程对象,此时它和普通的Java对象并没有区别。
好比一个美女出生并慢慢长大。
就绪状态的线程是具备被CPU调用的能力和状态,也只有这个状态的线程才能被CPU调用。
即线程调用了start()
好比这个美女被送进了宫。她此时可以被皇帝宠幸。
运行状态就是当前线程正在被CPU调度执行。
好比这个美女正在被宠幸。
运行->就绪 ①时间到②yield()
从运行状态到阻塞状态有几种情况:
①sleep()
②wait()
③join()
④没锁
⑤suspend()已过时
从阻塞回到就绪状态
①sleep()时间到,sleep()被打断interrupt()
②notify()
③加塞的线程结束
④占用锁的线程释放锁
⑤resume()已过时
从运行到死亡:①run()正常结束②run()遇到异常但是没处理③其他线程把你stop()(已过时)
主线程的名称:main
其他线程:默认是Thread-编号
优先级的范围:MIN_PRIORITY - MAX_PRIORITY ,[1,10]
普通优先级:NORM_PRIORITY
一共10个等级。
/*
* 2、案例:编写龟兔赛跑多线程程序,设赛跑长度为30米
兔子的速度是10米每秒,兔子每跑完10米休眠的时间10秒
乌龟的速度是1米每秒,乌龟每跑完10米的休眠时间是1秒
要求,
(1)每跑1米,显示一下结果:xxx跑了几米,
休息时,显示一下:xxx在休息...
(2)只要有跑完的,比赛就结束,最先跑完的就赢了,其他运动员就停下来别跑了
相当于,只比冠军
*/
public class TestExer08 {
public static void main(String[] args) {
//1、启动线程
Sportman t = new Sportman("兔子",30,100,10000);
Sportman w = new Sportman("乌龟",30,1000,1000);
t.start();
w.start();
//2、判断是否有运动员跑完了
while(true){
//如果有人跑完了,停下所有线程
if(t.isFinish() || w.isFinish()){
t.interrupt();
w.interrupt();
/* t.stop();
w.stop();*/
t.setStop(true);
w.setStop(true);
break;
}
}
//3、宣布结果
//看谁先跑完,谁就赢了
if(t.isFinish() && w.isFinish()){
System.out.println(t.getName() + "," + w.getName() + "平局");
}else if(t.isFinish()){
System.out.println(t.getName() + "赢了");
}else{
System.out.println(w.getName() + "赢了");
}
}
}
class Sportman extends Thread{
private int distance;//距离
private long runMillsPerMeter;//每米的时间,毫秒
private long restMillsPerTenMeter;//每10米休息的时间,毫秒
private long totalTime;
private volatile boolean finish;//默认值是false,如果跑完了,修改为true
private boolean stop;//默认值是false
public Sportman(String name, int distance ,long millsPerMeter, long restPerTenMeter) {
super(name);
this.distance = distance;
this.runMillsPerMeter = millsPerMeter;
this.restMillsPerTenMeter = restPerTenMeter;
}
public void run(){
long start = System.currentTimeMillis();
int i;
for (i = 1; i <= distance && !stop; i++) {
try {
Thread.sleep(runMillsPerMeter);//模拟跑1米的时间
} catch (InterruptedException e) {
e.printStackTrace();
}
//用线程名称代替运动员的名称
System.out.println(getName() + "跑了" + i + "米");
if(i= distance){//不是中途结束,而是全程跑完的
finish = true;
}
}
public long getTotalTime() {
return totalTime;
}
public boolean isFinish() {
return finish;
}
public void setStop(boolean stop) {
this.stop = stop;
}
}
举例:卖票
需要加锁的代码
public class Test09 {
public static void main(String[] args) {
Ticket t1 = new Ticket("窗口一");
Ticket t2 = new Ticket("窗口二");
Ticket t3 = new Ticket("窗口三");
t1.start();
t2.start();
t3.start();
}
}
class Ticket extends Thread{
private static int total = 1000;
private static Object lock = new Object();//锁的选择之一,单独造一个锁对象
public Ticket(String name) {
super(name);
}
public void run(){
// synchronized (this) {//这里使用this不行,因为这个this,对于三个线程来说不是同一个
while(true){
synchronized (lock) {
if(total > 0){
System.out.println(getName() + "卖出一张票");
total--;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("剩余:" + total);
}else{
break;
}
}
}
}
}
这一种更好,因为没有用到静态数据,静态数据生命周期太长,会影响之后对于这一类的使用
/*
* 步骤:
* (1)编写线程类,实现Runnable
* (2)重写run
* (3)创建线程对象
* (4)启动线程
*/
public class Test10 {
public static void main(String[] args) {
Ticket t = new Ticket();
Thread t1 = new Thread(t,"窗口一");
Thread t2 = new Thread(t,"窗口二");
Thread t3 = new Thread(t,"窗口三");
t1.start();
t2.start();
t3.start();
}
}
class Ticket implements Runnable{
private int total = 10;
@Override
public void run() {
while(true){
synchronized (this) {//选择this当锁,可以,因为只有一个Ticket的对象
if(total>0){
System.out.println(Thread.currentThread().getName() +"卖出一张票");
total--;
System.out.println("剩余:" + total);
}else{
break;
}
}
}
}
}
/*
* 同步方法的语法格式:
* 【修饰符】 synchronized 返回值类型 方法名(【形参列表】)throws 异常列表{
* }
*
* synchronized 【修饰符】 返回值类型 方法名(【形参列表】)throws 异常列表{
* }
*
* 同步方法的锁对象,程序员无法选择:
* (1)非静态方法:this
* (2)静态方法:当前类的Class对象
*/
public class Test11 {
public static void main(String[] args) {
Ticket t1 = new Ticket("窗口一");
Ticket t2 = new Ticket("窗口二");
Ticket t3 = new Ticket("窗口三");
t1.start();
t2.start();
t3.start();
}
}
class Ticket extends Thread{
private static int total = 10;
public Ticket(String name) {
super(name);
}
public void run(){
while(total>0){//程序停止的条件
saleOneTicket();
}
}
public synchronized static void saleOneTicket(){
if(total > 0){//线程安全问题的条件
System.out.println(Thread.currentThread().getName() + "卖出一张票");
total--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("剩余:" + total);
}
}
//同步方法,锁的是方法的一次调用过程
//非静态方法的锁对象是this,这里使用this,不是合格的锁对象
/*public synchronized void saleOneTicket(){
if(total > 0){//线程安全问题的条件
System.out.println(getName() + "卖出一张票");
total--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("剩余:" + total);
}
}*/
}
线程通信是用来解决生产者与消费者问题。
*
public class Test14 {
public static void main(String[] args) {
Workbench tai = new Workbench();
Cook c = new Cook("崔志恒", tai);
Waiter w = new Waiter("翠花", tai);
c.start();
w.start();
}
}
class Workbench{
//假设工作台上最多能够放10盘
private static final int MAX = 10;
private int count;
//同步方法,非静态方法来说,锁对象就是this
public synchronized void put(){//往工作台上放一盘菜
if(count >= MAX){
try {
//生产者停下来,等待
wait();//默认是this.wait()
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count++;
System.out.println(Thread.currentThread().getName() + "放了一盘菜,剩余:" + count);
this.notify();
}
public synchronized void take(){//从工作台上取走一盘菜
if(count<=0){
try {
//工作台没有菜,消费者应该停下来
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
System.out.println(Thread.currentThread().getName() + "取走一盘菜,剩余:" + count);
this.notify();
}
}
class Cook extends Thread{
private Workbench tai;
public Cook(String name, Workbench tai) {
super(name);
this.tai = tai;
}
public void run(){
while(true){
tai.put();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Waiter extends Thread{
private Workbench tai;
public Waiter(String name, Workbench tai) {
super(name);
this.tai = tai;
}
public void run(){
while(true){
tai.take();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
改良
/*
* 线程通信是用来解决生产者与消费者问题。
*
* 生产者与消费者问题:
* 有两个或者多个线程。
* 其中一个/一部分线程,生产“数据”,称为生产者线程;
* 另一个/一部分线程,消耗“数据”,称为消费者线程。
* 这些数据放在一个“共享”区域。
* 那么就会出现:
* 当“共享”区域中的数据空了,消费者线程必须"停/等待",等待到产者线程生产了新数据后,继续进行。
* 当“共享”区域中的数据满了,生产者线程必须"停下/等待",等到消费者线程消耗了数据后,继续进行。
*
* 生产者与消费者问题:
* (1)共享数据: 就会有线程安全问题,就需要同步
* (2)共享区域大小固定,有限的:就需要用到“协作”,线程通信。
*
* Object类中有:
* (1)wait():必须由锁对象(线程的监视器对象)来调用。
* (2)notify():必须由锁对象(线程的监视器对象)来调用。
* notify()作用就是唤醒一个正在等待的线程。唤醒的是同一个锁对象监视的等待线程。
* (3)notifyAll():唤醒所有和我是同一个监视器对象的正在等待的线程
*/
public class Test16 {
public static void main(String[] args) {
Workbench tai = new Workbench();
Cook c1 = new Cook("崔志恒", tai);
Cook c2 = new Cook("甄玉禄", tai);
Waiter w1 = new Waiter("翠花", tai);
Waiter w2 = new Waiter("如花", tai);
// Waiter w3 = new Waiter("秋香", tai);
c1.start();
c2.start();
w1.start();
w2.start();
// w3.start();
}
}
class Workbench{
//假设工作台上最多能够放10盘
private static final int MAX = 1;
private int count;
//同步方法,非静态方法来说,锁对象就是this
public synchronized void put(){//往工作台上放一盘菜
while(count >= MAX){
try {
//生产者停下来,等待
wait();//默认是this.wait()
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count++;
System.out.println(Thread.currentThread().getName() + "放了一盘菜,剩余:" + count);
this.notify();
}
public synchronized void take(){//从工作台上取走一盘菜
while(count<=0){
try {
//工作台没有菜,消费者应该停下来
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
System.out.println(Thread.currentThread().getName() + "取走一盘菜,剩余:" + count);
// this.notify();
this.notifyAll();
}
}
class Cook extends Thread{
private Workbench tai;
public Cook(String name, Workbench tai) {
super(name);
this.tai = tai;
}
public void run(){
while(true){
tai.put();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Waiter extends Thread{
private Workbench tai;
public Waiter(String name, Workbench tai) {
super(name);
this.tai = tai;
}
public void run(){
while(true){
tai.take();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
单例设计模式:
*
public class Test17 {
@Test
public void test1(){
SingleEnum s1 = SingleEnum.INSTANCE;
SingleEnum s2 = SingleEnum.INSTANCE;
System.out.println(s1 == s2);
}
@Test
public void test2(){
// SingleEnum.test();//此时我并没有需要用到这个对象,但是它也创建出来了
}
@Test
public void test3(){
SingleClass s1 = SingleClass.INSTANCE;
SingleClass s2 = SingleClass.INSTANCE;
System.out.println(s1==s2);
}
@Test
public void test4(){
Single s1 = Single.getInstance();
Single s2 = Single.getInstance();
System.out.println(s1 == s2);
}
@Test
public void test5(){
LazyClass s1 = LazyClass.getInstance();
LazyClass s2 = LazyClass.getInstance();
System.out.println(s2 == s1);
}
LazyClass s1;
LazyClass s2;
@Test
public void test6(){
//匿名的内部类,继承Thread类
Thread t1 = new Thread(){
public void run(){
s1 = LazyClass.getInstance();
}
};
Thread t2 = new Thread(){
public void run(){
s2 = LazyClass.getInstance();
}
};
t1.start();
t2.start();
try {
//这里用join的目的是,为了两个子线程都执行完,再执行主线程的System.out.println(s1);
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(s1);
System.out.println(s2);
System.out.println(s1 == s2);
}
}
enum SingleEnum{
INSTANCE;
// public static void test(){
// //..
// }
}
class SingleClass{
public static final SingleClass INSTANCE = new SingleClass();
private SingleClass(){
}
}
class Single{
private static final Single INSTANCE = new Single();
private Single(){
}
public static Single getInstance(){
return INSTANCE;
}
}
class LazyClass{
private static LazyClass instance;
private LazyClass(){
}
public static LazyClass getInstance(){
if(instance == null){//提高效率
synchronized(LazyClass.class){//当前类的Class对象
if(instance == null){//安全判断
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new LazyClass();
}
}
}
return instance;
}
//安全没问题,但是认为不是最优的
/* public synchronized static LazyClass getInstance(){
if(instance == null){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new LazyClass();
}
return instance;
}*/
//有安全问题
/* public static LazyClass getInstance(){
// return new LazyClass();//错误的
if(instance == null){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new LazyClass();
}
return instance;
}*/
}
class Lazy{
private Lazy(){
}
private static class Inner{
public static final Lazy INSTANCE = new Lazy();//在内部类中,创建外部类的唯一对象
}
public static Lazy getInstance(){
return Inner.INSTANCE;
}
}