黑马程序员-关于线程学习的若干总结

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

首先介绍下基本概念:

1, 进程:简单地讲,是一个正在执行的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫做控制单元。

2, 线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。一个进程中至少有一个线程。

3,Jvm 启动的时候会有一个进程 java.exe.该进程中至少一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。其实,jvm启动不止一个线程,还有一个负责垃圾回收机制的线程。

 

一:关于java多线程的实现问题:

在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。

对于直接继承Thread的类来说,代码大致框架是:

class类名extendsThread{

方法1;

方法2

publicvoidrun(){

// other code

}

属性1

属性2

 

}

注意主函数中要用d.start()方法开启线程并执行该线程的run方法。

通过实现Runnable接口:代码大致框架是:

class 类名 implements Runnable{

方法1;

方法2

public void run(){

// other code

}

属性1

属性2

 

}

Thread类继承的一个例子:

class hello extends Thread {

    public void run() {

        for (int i = 0; i < 7;i++) {

            if(count > 0) {

                System.out.println("count=" + count--);

            }

        }

    }

 

    public static void main(String[] args) {

        hello h1 = new hello();

        hello h2 = new hello();

        hello h3 = new hello();

        h1.start();

        h2.start();

        h3.start();

    }

 

    private int count = 5;

}

运行结果如下:

count=5

count=4

count=3

count=2

count=1

count=5

count=4

count=3

count=2

count=1

count=5

count=4

count=3

count=2

count=1

如果这个是一个买票系统的话,如果count表示的是车票的数量的话,说明并没有实现资源的共享。

我们换为Runnable接口

 

 

Runable接口的例子:

class MyThread implements Runnable{

 

    private int ticket = 5;  //5张票

 

    public void run() {

        for (int i=0; i<=20;i++) {

            if(this.ticket > 0) {

                System.out.println(Thread.currentThread().getName()+"正在卖票"+this.ticket--);

            }

        }

    }

}

public class lzwCode {

     

    public static void main(String [] args) {

        MyThread my = new MyThread();

        new Thread(my, "1号窗口").start();

        new Thread(my, "2号窗口").start();

        new Thread(my, "3号窗口").start();

    }

}

运行结果:

1号窗口正在卖票5

1号窗口正在卖票4

2号窗口正在卖票3

2号窗口正在卖票1

1号窗口正在卖票2

可以得出,实现Runnable接口比继承Thread类所具有的优势:

1):适合多个相同的程序代码的线程去处理同一个资源

2):可以避免java中的单继承的限制

3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。

 所以大家劲量实现runable接口。

 

二,关于多线程的安全问题:

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

来看看一个例子:一个简单的买票系统。

    public void run() {

        for(int i=0;i<10;++i){

            if(count>0){

                try{

                    Thread.sleep(100);

                }catch(InterruptedExceptione){

                    e.printStackTrace();

                }

                System.out.println(count--);

            }

        }

    }

 

    public static void main(String[] args) {

        hello he=new  hello();

        Thread h1=new Thread(he);

        Thread h2=new Thread(he);

        Thread h3=new Thread(he);

        h1.start();

        h2.start();

        h3.start();

    }

    private int count=5;

}

运行结果:

5

4

3

2

1

0

-1

出现了-1,显然这个是错的。应该票数不能为负值。

如果想解决这种问题,就需要使用同步。所谓同步就是在统一时间段中只有有一个线程运行,其他的线程必须等到这个线程结束之后才能继续执行。

使用线程同步解决问题

采用同步的话,可以使用同步代码块和同步方法两种来完成。

同步代码块:

语法格式:

synchronized(同步对象){

 //需要同步的代码

}

但是一般都把当前对象this作为同步对象。

比如对于上面的买票的问题,如下:

class hello implements Runnable {

    public void run() {

        for(int i=0;i<10;++i){

            synchronized(this) {

                if(count>0){

                    try{

                        Thread.sleep(100);

                    }catch(InterruptedExceptione){

                        e.printStackTrace();

                    }

                    System.out.println(count--);

                }

            }

        }

    }

 

    public static void main(String[] args) {

        hello he=new hello();

        Thread h1=new Thread(he);

        Thread h2=new Thread(he);

        Thread h3=new Thread(he);

        h1.start();

        h2.start();

        h3.start();

    }

    private int count=5;

}

运行结果:

5

4

3

2

1

 

现在来看看同步方法。

语法格式为synchronized 方法返回类型方法名(参数列表){

   // 其他代码

}

 

class hello implements Runnable {

    public void run() {

        for (int i = 0; i < 10;++i) {

            sale();

        }

    }

 

    public synchronized void sale() {

        if (count > 0) {

            try{

                Thread.sleep(100);

            }catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println(count--);

        }

    }

 

    public static void main(String[] args) {

        hello he = new hello();

        Thread h1 = new Thread(he);

        Thread h2 = new Thread(he);

        Thread h3 = new Thread(he);

        h1.start();

        h2.start();

        h3.start();

    }

 

    private int count = 5;

}

 

运行结果

5

4

3

2

1

 

对同步总结:

同步的前提:

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

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

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

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

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

 

三,单例设计模式

 

有两种。懒汉式和饿汉式

两种模式的区别:

懒汉式的特点是用于延迟加载。这种特点也会出现问题。

如果多线程访问时会出现安全问题。可以加同步的方式来解决。用同步代码块和同步函数都行。但是稍微有点低效,用判断的方式可以决绝效率问题。注意加同步的时候使用的锁是该类所属的字节码文件对象。

饿汉式class Lesson

{

       private static  finalSingle s = new Lesson ();

       private Lesson (){}

       public static Single getInstance()

       {

              return s;

       }

}

 

懒汉式:

class Lesson

{

       private static Single s = null;

       private Single(){}

       public static Single getInstance()

       {

              If(a==null)

              {

                     Synchronized(Single.class)

                     {

                            If(a==null)

                                   s = new Single();

                     }

              }

              return s;

       }

}

 

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

 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值