首页 > 代码库 > 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(多线程)