Java 多线程技术解析

匿名内部类

内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。

格式:

new 父类名 或 接口名(){
    重写父类的方法
};

代码举例:

// 利用给TreeSet 集合中的学生对象 按年龄排序
public class Demo02 {
    public static void main(String[] args) {
        TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        set.add(new Student("james", 19));
        set.add(new Student("Tom", 21));
        set.add(new Student("jerlly", 18));
        set.add(new Student("mike", 22));

        for (Student student : set) {
            System.out.println(student);
        }
    }

利用匿名内部类创建线程:

Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {
                System.out.println("启动");   
            }
        });
        thread.start();

线程的六种状态

1.新建状态 (new 线程对象)
2.运行状态 (调用 start()方法)
3.受阻塞状态 (等待CPU的执行资源)
4.休眠状态 (调用了sleep()方法)
5.等待状态 (调用了wait()方法)
6.死亡状态 (run()方法执行完毕)
这里写图片描述

线程休眠

线程休眠指线程调用了sleep()方法 让它在一定毫秒内执行线程休眠(暂停执行)

代码示例:

public class Demo04 {
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 100; i++) {
            // 线程休眠 1000 毫秒 
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
    }
}

class SleepThread extends Thread{
    /*
     * 如果子线程出现异常 只能try...catch(){} 处理
     * 
     * Thread 是Runnable 接口的实现类 重写了接口中的run()方法
     * 该方法没有抛出异常 所以所有Runnable 实现类(包括Thread类) 都不能在run()方法中抛出异常 只能自己处理
     */
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            // 线程休眠 1000 毫秒 
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
    }
}

多线程访问同一共享数据遇到的问题:

引入 synchronized 同步锁 概念

// 三种方式买票 分别使用三个线程 访问同一终端
public class Demo05 {
    public static void main(String[] args) {
        // 创建三条线程
        Ticket ticket = new Ticket();
        Thread t1 = new Thread(ticket);
        Thread t2 = new Thread(ticket);
        Thread t3 = new Thread(ticket);
        t1.start();
        t2.start();
        t3.start();
    }
}
/* 同步锁(同步代码块)
 * 锁 可以是任意对象 要保证 锁的唯一 三个线程 都使用的是同一把锁
 * synchronized (对象锁){
 *      
 * }  
 * 同步锁规则
 * 如果有锁 可以进去 携带锁进去 等出了同步代码块 当线程执行完代码块中的代码 把锁还回去 
 * 线程没有遇到锁 会在同步代码块等待 遇到锁才能进
 *
 */

class Ticket implements Runnable{
    // 保证票
    private int ticks = 100;
    // 创建了对象锁 保证了唯一
    private Object obj = new Object();

    @Override
    public  void run() {
        while (true) {
            // 锁只要保证是对象和唯一就可以 填 this也可以
            synchronized (obj) {
                // 操作的共享数据的代码
                if (ticks > 0) {
                    // 线程休眠
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    // 有票就卖
                    System.out.println(Thread.currentThread().getName() + "---" + ticks);
                    ticks --;
                }else {
                    // 没票 结束循环
                    break;
                }
            }
            // 让线程让出cpu资源
            Thread.yield();
        }
    }
}
/*
     * 解析: 
     *  如果不加 同步锁 会出现什么情况?
     *  会出现一张票被三个线程同时买到现象 
     *  那么为什么会出现这种情况呢?
     *  首先 三个线程调用start()方法 执行程序是随机的 系统调度会 随机让某个线程CPU提供的资源
     *  转移给另一个线程 但是这个线程恰好在获取余票却没有进行 总票 -1 情况 下一个线程也读取了
     *  同样的余票总数 因此出现错误 使用同步锁就不会出现这种情况!
     */

上面介绍了同步锁代码块的写法和作用 下面介绍同步锁的另一种写法:

// 在方法中添加 synchronized 关键词 把方法变成同步方法
public static synchroized void name(){
    //do something
}

//当方法是静态方法时 使用同步代码块时 可以不必创立一个对象锁传入同步代码块中
// 可以直接使用 本类 类名.class
synchroized(类名.class){
    // do something
}

死锁

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。

模拟死锁代码:

public class Demo07 {
    public static void main(String[] args) {
        TestSync test = new TestSync();
        Thread thread = new Thread(test);
        Thread thread2 = new Thread(test);
        thread.start();
        thread2.start();
    }
}

class TestSync implements Runnable{
    private boolean isTrue = true;
    @Override
    public void run() {
        while (true) {
            if (isTrue) {
                // A锁 ---> B锁
                synchronized (LockA.LOCK_A) {
                    System.out.println("if....LOCK_A");
                    synchronized (LockB.LOCK_B) {
                    System.out.println("if...LOCK_B");  
                    }
                }
            }else {
                // B锁 ---> A锁
                synchronized (LockB.LOCK_B) {
                    System.out.println("else...LOCK_B");
                    synchronized (LockA.LOCK_A) {
                        System.out.println("else...LOCK_A");
                    }
                }
            }
            // 修改标记
            isTrue = !isTrue;
        }       
    }   
}
// A锁对象
class LockA{
    public LockA() {
    }
    public static final LockA LOCK_A = new LockA();

}

class LockB{
    public LockB() {

    }
    public static final LockB LOCK_B = new LockB(); 
}

Lock 接口

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。 从java 1.5 开始

实现步骤:

Lock l = ...; 
     l.lock();
     try {
         // access the resource protected by this lock
     } finally {
         l.unlock();
     }

代码示例:

public class Demo08 {
    public static void main(String[] args) {
        Titkets1 test = new Titkets1();
        Thread thread = new Thread(test);
        Thread thread2 = new Thread(test);
        Thread thread3 = new Thread(test);
        thread.start();
        thread2.start();
        thread3.start();
    }
}

class Titkets1 implements Runnable{
    private int num = 100;
    //声明锁对象
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            // 加锁
            lock.lock();
            try {
                // 锁住操作共享数据的代码
                if (num >0) {
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "---" + num --);
                }else {
                    break;
                }
            } finally {
                lock.unlock();
            }
            Thread.yield();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值