Java-线程、同步-第17节

学习目标:

  • 学会怎么获取与设置线程的名字
  • 掌握创建多线程程序的第二种方式
  • 理解多线程共享数据的安全问题
  • 掌握解决安全问题的三种办法,能够熟练使用锁机制

学习内容:

一、Thread的常用方法
1、获取线程的名称
  • 使用Thread类中的getName方法
    • String getName()
  • 先获取正在执行的线程,再用线程中的方法getName获取线程的名称
    • static Thread currentThread() 返回对当前正在执行的线程对象的引用
2、设置线程名称
  • 使用setName方法
  • 直接在子类中调用父类的name的构造方法,主函数中创建子类对象直接传递线程名
3、设置线程暂停执行
  • public static void sleep(long Millis);
二、创建多线程程序的第二种方式
1、实现Runnable接口
  • 实现步骤
    • 创建一个Runnable接口的实现类
    • 在实现类中重写run方法,实现功能
    • 创建实现类对象
    • 创建Thread对象,构造方法中传递实现类对象
    • 调用Thread类的start方法,创建新的线程
  • 两种实现方式的区别
    • 实现Runnable接口避免了单继承的局限性
      使用创建Thread子类的方法只能继承一个父类,二实现Runnable能够实现多个接口
    • 实现Runnable接口增强了程序的扩展性,降低了程序的耦合性
      把设置线程任务与开启新线程进行了分离(解耦)
2、匿名内部类创建线程
  • 简介
    • 匿名:没有名字
    • 内部类:写在其他类的内部的类
    • 简化代码
  • 最终产物
    • 子类/实现类对象(没有名字)
三、多线程共享数据安全问题

在这里插入图片描述

1、安全问题的产生

在这里插入图片描述

  • 多线程执行的冲突
2、安全问题的解决方法
  • 使用同步代码块
    • 使用形式
      synchronized(object obj){
      代码块内容;
      }
    • 内部执行步骤
      • 当一个线程抢到CPU控制权,执行到同步代码块时,会将对应的锁对象obj拿到手,直到执行
      • 代码块中内容完毕,才会将对象还回同步代码块;
      • 当一个线程执行到同步代码块,而没有锁对象,那么不会继续往下执行,会等待锁对象
    • 缺点
      • 频繁的切换锁会导致效率低下
  • 使用同步方法
    • 使用形式
      public synchronized void 方法名(){
      方法体,需要同步的内容;
      }
    • 使用步骤
      • 先定义同步方法
      • 在重写run方法中调用
    • 注意
      • 同步对象就是this,即创建的实现类对象
    • 静态同步方法
      • 对象不能是this,而是对应的实现类(实现类名.class)
  • 使用Lock锁
    • 简介
      • java.util.concurrent.Locks.Lock接口
      • 方法:
        • void lock(); 获取锁
        • void unlock(); 释放锁
          java.util.concurrent.Locks.ReentrantLock 实现类
    • 使用步骤
      • 在成员位置创建一个ReentrantLock对象
      • 在可能出现安全问题的代码前调用Lock接口的lock方法,获取锁
      • 在可能出现安全问题的代码后调用Lock接口的unlock方法,释放锁
    • 注意
      • 使用锁时最好用try catch,这样就算代码异常也会释放锁
四、线程状态

在这里插入图片描述

1、概述
  • NEW

    • 新建,尚未启动,即还没调用start方法
  • Runnable

    • 可运行,可能正在运行自己的代码,也可能没有
  • Blocked
    在这里插入图片描述

    • 锁阻塞,当一个线程尝试获取一个对象锁,而该对象锁被其他线程持有
  • Waiting
    在这里插入图片描述

    • 无限等待,一个线程等待另一个线程执行唤醒(notify)动作进入的状态,不能自动唤醒,
    • 只能等待另一个线程调用notify或notifyAll方法才能够被唤醒
  • Timed Waiting
    在这里插入图片描述

    • 计时等待,超时自动唤醒
  • Teminated

    • 被终止,因为run方法正常退出或因没有捕获的异常而终止了run方法而死亡

学习产出:

1、秒表

package mypackage.day13.demo01;

public class SleepMethod {
    public static void main(String[] args) {
        for (int i = 0; i < 60; i++) {
            System.out.println(i+1);
            try {
                Thread.sleep(1000);
            } catch (Exception e){
                e.getStackTrace();
            }
        }

    }
}

2、获取线程名

package mypackage.day13.demo01;

public class GetNameClass extends Thread {
    @Override
    public void run() {
        // 直接获取线程名称
        String name = getName();
        System.out.println(name);

        System.out.println(currentThread().getName());
    }
}

package mypackage.day13.demo01;

public class DemoGetThreadName {
    public static void main(String[] args) {
        GetNameClass aClass = new GetNameClass();
        aClass.start();
        new GetNameClass().start();
        new GetNameClass().start();

        System.out.println(Thread.currentThread().getName());
    }
}

3、 设置线程名

package mypackage.day13.demo01;

public class SetName extends Thread{
    public SetName() {
    }

    public SetName(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

package mypackage.day13.demo01;

public class SetNameMain {
    public static void main(String[] args) {
        SetName thread = new SetName();
        thread.setName("Jim");
        thread.start();

        new SetName("Tom").start();

        System.out.println("当前线程:"+Thread.currentThread().getName());
    }
}

4、创建多线程程序的第二种方式:实现Runnable接口

package mypackage.day13.demo02;

public class MultiThread implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}

package mypackage.day13.demo02;

import mypackage.day13.demo02.MultiThread;

public class MultiThreadMain {
    public static void main(String[] args) {
        MultiThread multiThread = new MultiThread();
        new Thread(multiThread).start();
        new Thread(multiThread).start();
    }
}

5、匿名内部类创建多线程程序

package mypackage.day13.demo02;

public class NoNameMultiThread {
    public static void main(String[] args) {
        // 创建Thread子类
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println("Thread1--->"+i);
                }
            }
        }.start();

        // 创建Runnable实现类
        new Thread(new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println("Thread2--->"+i);
                }
            }
        }).start();
    }
}

6、多线程共享数据安全问题

package mypackage.day13.demo02;

public class SecurityMultiThread implements Runnable{
    private int ticket = 100;
    @Override
    public void run() {
        while (true){
            if (ticket>0){
                System.out.println(Thread.currentThread().getName()
                        +"正在卖第"+ticket+"张票!");
                ticket--;
            }
        }
    }
}

package mypackage.day13.demo02;

public class SecurityMain {
    public static void main(String[] args) {
        SecurityMultiThread multiThread = new SecurityMultiThread();
        new Thread(multiThread).start();
        new Thread(multiThread).start();
        new Thread(multiThread).start();
    }
}

7、安全问题的解决方法

方法一
package mypackage.day13.demo03;

public class DealSecurityMethod1 implements Runnable{
    private int ticket = 100;
    @Override
    public void run() {
        while (true){
            Object obj = new Object();
            synchronized (obj){
                if (ticket>0){
                    System.out.println(Thread.currentThread().getName()
                            +"正在卖第"+ticket+"张票!");
                    ticket--;
                }
            }
        }
    }
}

方法二
package mypackage.day13.demo03;

public class DealSecurityMethod2 implements Runnable{
    private int ticket = 100;
    @Override
    public void run() {
        while (true){
            sellTicket();
            if (ticket==0){
                break;
            }
        }
    }
    public synchronized void sellTicket(){
        if (ticket>0){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()
                    +"正在卖第"+ticket+"张票!");
            ticket--;
        }
    }
}

方法三
package mypackage.day13.demo03;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class DealSecurityMethod3 implements Runnable{
    private int ticket = 100;
    private Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            lock.lock();
            if (ticket>0){
                try {
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName()
                            +"正在卖第"+ticket+"张票!");
                    ticket--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
            if (ticket==0){
                break;
            }
        }
    }
}

package mypackage.day13.demo03;

public class SecurityMain {
    public static void main(String[] args) {
        DealSecurityMethod3 multiThread = new DealSecurityMethod3();
        new Thread(multiThread).start();
        new Thread(multiThread).start();
        new Thread(multiThread).start();
    }
}

8、wait、notify案例
在这里插入图片描述

package mypackage.day13.demo04;

public class DemoWaitNotify {
    public static void main(String[] args) {
        Object obj = new Object();
        new Thread(){
            @Override
            public void run() {
                while (true){
                    System.out.println("告诉需求。。。");
                    synchronized (obj){
                        obj.notify();
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("包子做好了,开吃");
                    System.out.println("=================");
                }
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                while (true){
                    System.out.println("开始做包子--------");
                    try {
                        sleep(5000);
                        System.out.println("做好包子,上菜!!!");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (obj){
                        obj.notify();
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }.start();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值