首页 > 代码库 > JAVA基础9(多线程)
JAVA基础9(多线程)
1:多线程
(1)线程是依赖于进程而存在的。
A.进程正在运行的应用程序
B.线程进程的执行路径,执行单元
(2)多线程的两种方案:
继承Thread类:
实现Runable接口:
public class MyThread implements Runnable{
//实现runnable接口
public void run() {
//启动该线程对象之后,需要执行的代码
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
}
public class MyThread extends Thread{
//1.继承Thread类
//2.重写run方法
public void run() {
//开启该线程之后,执行一个for循环
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
}
(3)多线程的几个问题:
A.启动线程的方法
start()
B.start()和run()的区别
start():1.开启线程 2.执行run()方法里面的代码
run():执行的是线程里面执行的代码,并不会开启线程
C.重写run()
因为每个线程需要执行的代码都是都是不一样的,
我们需要将每个线程自己独立执行的代码写到run()方法中执行
D.线程不可以多次启动
(4)线程的调度和控制
线程休眠(Thread.sleep(毫秒值))
线程名称(setName(),getName();)
线程的调度及优先级setPriority(10)(注意默认值是5,区间在1-10之间)
线程优先级:设置抢占cpu执行权抢占到的概率
(5)多线程案例(两种方式实现,睡一会出现线程安全问题):
继承Thread卖票
实现Runnable卖票(睡一会出现线程安全问题)
按照真实的情景加入了延迟,出现了两个问题:
A.相同的票卖了多次
CPU的一次操作必须是原子性的(操作是CPU执行一次就可以直接完成的)
B.出现了负数的票
随机性和延迟导致的
出现上面的问题称为线程安全问题。
public class MyThread extends Thread{
//共有100张票,将ticket改为静态之后,被类的所有对象所共享
static int ticket = 100;
public void run() {
//用一个while true循环模拟三个窗口一直处于打开的状态
while (true) {
//只有当ticket>0的时候,才可以出售票
if (ticket>0) {
System.out.println(getName()+"正在出售第:"+ticket--+"张票");
}
}
}
}
public class Test {
public static void main(String[] args) {
//创建三个线程模拟三个售票窗口
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
MyThread mt3 = new MyThread();
//给线程设置名称
mt1.setName("窗口一");
mt2.setName("窗口二");
mt3.setName("窗口三");
//启动线程,开启售票
mt1.start();
mt2.start();
mt3.start();
}
}
(6)多线程安全问题
A.是否是多线程环境
B.是否有共享数据
C.是否有多条语句操作共享数据
(7)如何解决多线程安全问题
线程安全执行效率就低
A.同步代码块(测试不是同一个锁的情况,测试是同一个锁的情况)
synchronized(对象) {
需要被同步的代码。
}
B.两个问题:1.对象是什么 ?
答:任意对象 ,相当于是一把锁,只要线程进去就把锁锁上
2.需要同步的代码?
答:被线程执行的代码
C.锁对象问题
a.同步代码块(定义一个抽象类,里面专门定义一个锁)
任意对象
b.同步方法(仅适用于实现runable接口)
public synchronized voidsellTicket(){同步代码}
this
c.静态同步方法
类的字节码对象
public static synchronized voidsellTicket() {
需要同步的代码
}
public class MyThread implements Runnable{
//定义100张票
int ticket = 100;
Object obj = new Object();
public void run() {
while (true) {
//同步代码块
synchronized (obj) {//3个线程才可以共享同一把锁
if (ticket>0) {
//考虑到实际,我们需要给每一个线程加入一定的延迟,模拟一下这种效果
try {
Thread.sleep(100);
/**
* 分析:为什么会出现两张100张票
* t1抢占到cpu的执行权,此时ticket=100,但是此刻休眠了
* 此时被t2抢占到了cpu的执行权,此时ticket=100,
* t1,t2分别睡了100毫秒之后,分别醒来了
* t1此时出售第100张票
* t2此时出售第100张票
*/
/**
* 分析:为什么会出现0张票和-1张票
* 假设此时票池中仅剩1张票了,
* t1进来休眠了
* t2进来休眠了
* t3进来休眠了
*/
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票");
}
}
}
}
}
public class Test {
public static void main(String[] args) {
//创建MyThread对象
MyThread mt = new MyThread();
//创建三个窗口
Thread t1 = new Thread(mt);
Thread t2 = new Thread(mt);
Thread t3 = new Thread(mt);
//给每一个窗口设置姓名
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
//开启窗口进行售票
t1.start();
t2.start();
t3.start();
}
}
(8)匿名内部类的方式使用多线程
new Thread() {
public void run() {
...
}
}.start();
new Thread(new Runnable(){
public void run() {
...
}
}).start();
(9) JDK5的Lock锁,我们之前造的所有的锁都没有手动释放锁
static Lock lock = new ReentrantLock();
枷锁:lock.lock();
释放锁:lock.unlock();
可以让我们明确的知道在哪里加锁和释放锁。
依然写一个卖票的demo,用lock枷锁释放锁,
为了保证我们创建的锁一定会被释放,用一下代码进行改进
try{....}finally{.....}
(10)死锁问题
同步嵌套,锁里面套了一个锁,出现同步嵌套
(11)线程等待和唤醒机制
锁对象调用wait()锁对象调用notify()
注意:
wait和sleep的区别
线程等待,在等待的同时释放锁,而sleep()方法在执行的过程中是不会释放锁的
JAVA基础9(多线程)