天天看点

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、匿名内部类创建线程
  • 简介
    • 匿名:没有名字
    • 内部类:写在其他类的内部的类
    • 简化代码
  • 最终产物
    • 子类/实现类对象(没有名字)

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

Java-线程、同步-第17节学习目标:学习内容:学习产出:
1、安全问题的产生
Java-线程、同步-第17节学习目标:学习内容:学习产出:
  • 多线程执行的冲突
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,这样就算代码异常也会释放锁

四、线程状态

Java-线程、同步-第17节学习目标:学习内容:学习产出:
1、概述
  • NEW
    • 新建,尚未启动,即还没调用start方法
  • Runnable
    • 可运行,可能正在运行自己的代码,也可能没有
  • Blocked
    Java-线程、同步-第17节学习目标:学习内容:学习产出:
    • 锁阻塞,当一个线程尝试获取一个对象锁,而该对象锁被其他线程持有
  • Waiting
    Java-线程、同步-第17节学习目标:学习内容:学习产出:
    • 无限等待,一个线程等待另一个线程执行唤醒(notify)动作进入的状态,不能自动唤醒,
    • 只能等待另一个线程调用notify或notifyAll方法才能够被唤醒
  • Timed Waiting
    Java-线程、同步-第17节学习目标:学习内容:学习产出:
    • 计时等待,超时自动唤醒
  • 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案例

Java-线程、同步-第17节学习目标:学习内容:学习产出:
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();
    }
}