------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! ----

来源:互联网 发布:软件板块指数 编辑:程序博客网 时间:2024/04/25 04:56
黑马程序员 多线程

创建线程的两种方式:
继承Thread类,覆盖.run()方法,在子类创建对象时,线程就建立了。.start()方法启动线程。如果不启动,直接.run()方法,这时run()方法的内容还是主线程运行的。多线程根本没有启动。

 

实现Runnable接口,实现.run()方法,创建Thread类对象,将Runnable的子类以参数形式传递到Thread类的构造方法中。 然后Thread类的对象.start()方法,启动线程。此种方式为:当多个线程执行中一资源。

 

区别:当一个类已经继承了一个类,但还需要执行多线程。这时,就不能继承Thread类了,因为java只支持单继承。

 

售票的例子:

用继承Thread类的方法做,会发现每创建一个线程,他们中的资源都是独立的。所以每个线程都有100张票。虽然可以用 private static int count=100;但不建议用静态,因为生命周期太长。

class Ticket extends Thread {

    private int count = 100;

    @Override

    public void run() {

        // TODO Auto-generated method stub

        while (true) {

 

            if (count > 0) {

 

                System.out.println(Thread.currentThread().getName()

                        +"-----------" + count--);

            }

        }

    }

}

 

public classThreadDemo1 {

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        Tickett1 = newTicket();

        Tickett2 = newTicket();

        Tickett3 = newTicket();

        Tickett4 = newTicket();

 

        t1.start();

        t2.start();

        t3.start();

        t4.start();

    }

}

 

IllegalThreadStateException:无效线程状态异常。 

                                  一个线程多次start( )开启,会报此异常。

 

 

实现Runnable方式

class Ticket implements Runnable {

    private int count = 200;

    @Override

    public void run() {

        // TODO Auto-generated method stub

        while (true) {

            if (count > 0) {

                System.out.println(Thread.currentThread().getName()

                        +"-----------" + count--);

            }else{

                break;

            }

        }

    }

}

 

public classThreadDemo1 {

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        Tickett = newTicket();

 

        Threadt1 = newThread(t);

        Threadt2 = newThread(t);

        Threadt3 = newThread(t);

        Threadt4 = newThread(t);

 

        t1.start();

        t2.start();

        t3.start();

        t4.start();

    }

}

 

可能会打印出0,-1,-2等数据的情况。原因分析

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完。另一个线程参与进来扫行,导致共享数据的错误。

解决办法:对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。

JAVA对于多线程的安全问题提供了专业的解决方式。

就是同步代码块:

synchronized(对象){

     需要被同步的代码

}

 

对象 可以看做一个标志位,有两个值1和0, 当一个线程进入同步后,将对象改为0。其它线程则无法进入。专业术语就是锁。

 

同步的前提:

1, 必须要有两个或者两个以上的线程。

2, 必须多个线程使用同一个锁。

 

必须保证同步中只能有一个线程在运行。

 

好处:解决了多线程的安全问题。

弊端:多个线程需要判断锁,较为消耗资源。


同步函数:

       在函数上加上synchronized修饰符即可

 

      同步的表现形式:
       1,同步代码块。
       2,同步函数。
       两者有什么不同:
       同步代码块使用的锁是任意对象。
       同步函数使用的锁是this。

 

       注意:对于static的同步函数,使用的锁不是this。是 类名.class 是该类的字节码文件对象。 涉及到了单例设计模式的懒汉式。

 

       同步的好处:解决了线程的安全问题。

       弊端:
        较为消耗资源。
        同步嵌套后,容易死锁。

       要记住:同步使用的前提:
        1,必须是两个或者两个以上的线程。
        2,必须是多个线程使用同一个锁。
       这是才可以称为这些线程被同步了。

 

       死锁:同步中嵌套同步,而锁却不同

 

      wait(),notify(),notifyAll(),这些方法用于同步中。因为要对持有监视器(锁)的线程操作,所以要使用在同步中,因为只有同步还有锁。

      notify()其实调用的就是wait(0)

      

      为什么这些操作的方法要定义到Object类中?

    因为这些方法在操作同步中线程 时,都必须要标识它们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被同一个锁上的notify()唤醒。不可对不同锁的notify唤醒。也就是说,wait和notify必须 是一个锁。而锁可以是任意对象。任意对象的方法都定义在object类中。

 

 

将同步Synchronized替换成现实Lock操作。

       Object中的waitnotifynotifyAll,替换了Condition对象。

      

       将同步Synchronized替换成现实Lock操作。

Object中的waitnotifynotifyAll,替换了Condition对象。

该对象可以Lock锁 进行获取。

该示例中,实现了本方只唤醒对方操作。

 

Lock:替代了Synchronized

       lock

       unlock

       newCondition()

 

Condition:替代了Object wait notify notifyAll

       await();

       signal();

       signalAll();

 

停止线程

       stop方法已经过时,不再使用

       如果停止线程:只有一个方法,run方法结束

       当开启多个线程运行,运行代码通常是循环结构,只要控制了循环,就可以让run方法结束

 

特殊情况

       当线程处于冻结状态,就不会读取标记,那么线程就不会结束。

       interrupt()强制清除冻结、等待状态,会执异常

       当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除,

       强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束

       Thread提供interrupt()方法

 

setDaemon(booleanb)     守护线程

后台线程,依靠前台线程,前台线程都结束后,后台线程不管有没有执行完run方法都会结束

 

join():抢夺CPU的执行权

       A线程执行到B线程的Join()方法时,A就会等待,等B线程执行完,A再执行

 

setPriority(intnum)getPriority():设置和返回线程优先级



0 0