Java学习笔记(十五)--线程

多线程

1.线程是依赖于进程而存在
(1)进程:正在运行的应用程序
(2)线程:进程的执行路径,执行单元

2.多线程的两种方案
(1)继承Thread类;

package com.edu_01;

public class MyThread extends Thread{
    //1.继承Thread类
    //2.重写run方法,重写run方法中的代码之后,当我们启动了这个线程之后,我们的这个线程就会执行run方法中的代码
    @Override
    public void run() {
        //需求:开启该线程之后,执行一个for循环
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }
    }

}

(2)实现Runnable接口。

package com.edu_01;

public class MyThread implements Runnable{
    @Override
    public void run() {
        //启动该线程对象之后,需要执行的代码
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }   
    }

}

3.多线程的几个问题
(1)启动多线程:start()方法
start()方法的两个作用
第一:开启一个独立的线程;
第二:让新线程执行run()方法中的代码。
(2)start()和run()的区别:
start():1.开启线程 2.执行run()方法里面的代码
run():执行的是线程里面执行的代码,并不会开启线程
(3)重写run():因为每一个线程需要执行的代码都不一样。
(4)线程不可以多次启动。

4.线程休眠:Thread.sleep(long millis)
:在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。

5.线程名称
setName(String name):改变线程名称
getName():返回该线程的名称

6.线程的调度及优先级
(1)线程的优先级:设置线程抢占CPU的概率(肉眼上,多个线程同时执行,本质上,CPU在一个时间点上只能执行一个任务。)。
(2)setPriority(int newPriority):更改线程的优先级,默认值是5,区间在1-10之间。


多线程安全问题

1.多线程安全问题
(1)是否是多线程环境;
(2)是否有共享数据;
(3)是否有多条语句操作共享数据。

2.如何解决多线程安全问题
(1)同步代码块

synchronized(对象) {
            需要被同步的代码。
        }

注意三点
第一,对象:任意对象,这个对象就成为锁,只要线程进去就把锁锁上;
第二,需要被同步的代码:会出现线程安全问题的代码;
第三,同步代码块对锁的要求:需要多个线程共享一把锁。
(2)锁对象问题
A:同步代码块(定义一个抽象类,里面专门定义一个锁):任意对象。
B:同步方法(仅适用于实现Runnable接口):将synchronized关键字加到方法上,同步方法的锁是this。
例如:多线程售票问题。

private synchronized void sellTicket() {    
        //需要同步的代码
        if (ticket>0) {
                //考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票");
        }
}

C:静态同步方法:它的锁是本类的字节码文件对象:类名.class。例如:synchronized (MyThread.class)

    private static synchronized void sellTicket() {
    //需要同步的代码   
    if (ticket>0) {
            //考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票");

    }

匿名内部类的方式使用多线程

1.继承Thread类

new Thread() {
    public void run() {
            ...
    }
}.start();

2.实现Runnable接口

new Thread(new Runnable(){
    public void run() {
            ...
    }
}).start();

JDK5的Lock锁

1.Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。

static Lock lock = new ReentrantLock();
lock.lock();//加锁
lock.unlock();//释放锁

2.void lock()获取锁。 如果锁不可用,出于线程调度目的,将禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态。

3.void unlock()释放锁。

4.不使用块结构锁就失去了使用 synchronized 方法和语句时会出现的锁自动释放功能。为了保证我们创建的锁一定会被释放,用以下代码进行改进:

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

5.死锁问题:同步嵌套,锁里面套了一个锁,会出现死锁问题,所以以后写代码的过程中尽量避免同步嵌套。


线程等待和唤醒机制

案例:waitThread,NotifyThread,MyLock,Test。
获取锁对象

package com.edu_01;

public abstract class MyLock {
    public static final Object obj = new Object();

}

等待机制

package com.edu_01;

public class WaitThread extends Thread{

    @Override
    public void run() {
        synchronized (MyLock.obj) {
            //让等待线程处于等待状态
            try {
                MyLock.obj.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println("我被唤醒了");
    }

}

唤醒机制

package com.edu_01;

public class NotifyThread extends Thread{
    @Override
    public void run() {
        synchronized (MyLock.obj) {
            //唤醒等待线程
            MyLock.obj.notify();//唤醒正在等待的线程,唤醒的等待线程的锁对象,必须和等待线程的锁对象一致
        }
    }

}

测试类

package com.edu_01;

public class Test {
    public static void main(String[] args) {
        //创建等待线程,让等待线程处于一个等待状态
        WaitThread wt = new WaitThread();
        wt.start();

        //睡上5秒钟之后唤醒等待线程
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        //创建唤醒线程对象
        NotifyThread nt = new NotifyThread();
        nt.start();

    }

}

wait()和sleep()的区别
wait():线程等待的过程中,程序不会继续往下执行了,等待的同时会释放掉手中的锁。
sleep():在线程休眠的过程中,不会释放手中的锁。

注意
唤醒正在等待的线程,唤醒的等待线程的锁对象,必须和等待线程的锁对象一致。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值