java多线程基础


一、简单线程的实现 1、Runnable接口实现多线陈      1.1、将任务代码移到实现了Runnable接口的类的run方法中。这个接口非常简单,只有一个方法
public interface Runnable     void run(); 可以如下所示实现一个类:
class MyRunnable implements Runnable     public void run(){          do something     }
     1.2、创建一个类对象:
Runnable r = new MyRunnable();
1.3、由Runnable创建一个Thread对象:
Thread t = new Thread(r);
1.4、启动线程
t.start();
2.继承Thread类实现多线程      2.1、继承Thread类并重写run方法,将任务代码写进run方法中
- public class MyThread extends Thread {-   public void run() {-    System.out.println("MyThread.run()");-   }- }      2.2、启动线程       - MyThread myThread1 = new MyThread();- MyThread myThread2 = new MyThread();- myThread1.start();- myThread2.start();
二、Thread和Runnable的区别       其实Thread的run方法也是调用的Runnable的run方法,但是他们有什么区别呢?    1、  如果一个类继承了Thread,类只能是单继承。但如果实现了Runnable接口的话,可以实现多个接口。 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为剩余的车票数,上面的h1,h2,h3为三个人同时买票,那么就会出现问题了。
下面我们把Thread换为Runnable 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();    }}

【运行结果】:

count= 5

count= 4

count= 3

count= 2

count= 1

2、实现Runnble接口比继承Thread类所具有的优势      2.1 适合多个相同的代码线程去处理同一个资源      2.1可以避免java中的多线程限制      2.3 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。 所以建议尽量用接口来实现多线程。
注:     提醒一下大家:main方法其实也是一个线程。在java中所以的线程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源。     在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个jVM实习在就是在操作系统中启动了一个进程。

三、线程的一些常用方法     3.1 设置线程的优先级:线程默认的优先级是创建它的执行线程的优先级。可以通过setPriority(int newPriority)更改线程的优先级。优先级代表的是概率,并不是绝对的优先级。例如:       Thread t = new MyThread();        t.setPriority(8);        t.start();
     线程优先级为1~10之间的正整数,JVM从不会改变一个线程的优先级。然而,1~10之间的值是没有保证的。一些JVM可能不能识别10个不同的值,而将这些优先级进行每两个或多个合并,变成少于10个的优先级,则两个或多个优先级的线程可能被映射为一个优先级。      线程默认优先级是5Thread类中有三个常量,定义线程优先级范围:static int MAX_PRIORITY           线程可以具有的最高优先级。static int MIN_PRIORITY           线程可以具有的最低优先级。static int NORM_PRIORITY           分配给线程的默认优先级。 3.2Thread.yield()方法      Thread.yield()方法作用是:暂停当前正在执行的线程对象,并执行其他线程。yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。 3.3、join()方法      Thread的非静态方法join()让一个线程B“加入到另外一个线程A的尾部。在A执行完毕之前,B不能工作。例如:        Thread t = new MyThread();        t.start();        t.join();
另外,join()方法还有带超时限制的重载版本。例如t.join(5000);则让线程等待5000毫秒,如果超过这个时间,则停止等待,变为可运行状态。
四、同步     同步又称为并发,即多个线程访问同一个资源,要确保资源安全,即线程安全。     多个线程同时访问一个资源,会造成一些问题。比如还是买车票的问题,如果在一个时间点上,两个线程同时使用这个资源,那他们取出的火车票是一样的(座位号一样),这样就会给乘客造成麻烦。
class MyThread implements Runnable{
    private int ticket = 10;  //5张票
    public void run() {
        for (int i =0; i<=20; i++) {
            if (this .ticket > 0) {                System. out .println(Thread.currentThread().getName()+ "正在卖票" + this. ticket--);            }        }    }
    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、同步块          即在run方法中假如synchronized块,来保证每一次只有一个线程进来。          
class MyThread implements Runnable{
    private int ticket = 10;  //5张票
    public void run() {
        for (int i =0; i<=20; i++) {             synchronized (this ){            if (this .ticket > 0) {                   try {                              Thread. sleep(500);                        } catch (Exception e ) {                               e.printStackTrace();                        }                System. out .println(Thread.currentThread().getName()+ "正在卖票" + this. ticket--);            }        }        }    }
    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();    }}
运行结果:可以看出结果正常。
     2、同步方法          从1.0版本开始,java的每个对象都有一个内部锁。如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法。          public synchronized void method(){               //do something          }买票代码改进如下
class MyThread implements Runnable{
    private int ticket = 10;  //10张票
    public void run() {
        for (int i =0; i<=20; i++) {             if (this .ticket > 0) {                   try {                              Thread. sleep(500);                        } catch (Exception e ) {                               e.printStackTrace();                        }            }            sale();    }   }        public synchronized void sale(){         if (this .ticket > 0) {
               System. out .println(Thread.currentThread().getName()+ "正在卖票" + this. ticket--);           }
    }
    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();    }}
显示结果
     3、死锁          过多的同步容易造成死锁           是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。              死锁是因为多线程访问共享资源,由于访问的顺序不当所造成的,通常是一个线程锁定了一个资源A,而又想去锁定资源B;在另一个线程中,锁定了资源B,而又想去锁定资源A以完成自身的操作,两个线程都想得到对方的资源,而不愿释放自己的资源,造成两个线程都在等待,而无法执行的情况。         下面从网上找了一个图,很形象的说明了此问题

package com.slowly.tongbu;
class Zhangsan{ // 定义张三类       public void say(){      System. out .println("张三对李四说:“你给我画,我就把书给你。”" ) ;      }       public void get(){            System. out .println("张三得到画了。" ) ;      }}class Lisi{ // 定义李四类       public void say(){      System. out .println("李四对张三说:“你给我书,我就把画给你”" ) ;      }       public void get(){            System. out .println("李四得到书了。" ) ;      }}public class ThreadDeadLock implements Runnable{       private static Zhangsan zs = new Zhangsan() ; // 实例化static型对象       private static Lisi ls = new Lisi() ; // 实例化static型对象       private boolean flag = false ; // 声明标志位,判断那个先说话       public void run(){ // 覆写run()方法             if (flag ){                   synchronized (zs ){ // 同步张三                         zs .say() ;                         try {                              Thread. sleep(500) ;                        } catch (InterruptedException e ){                               e.printStackTrace() ;                        }                         synchronized (ls ){                               zs .get() ;                        }                  }            }             else {                   synchronized (ls ){                         ls .say() ;                         try {                              Thread. sleep(500) ;                        } catch (InterruptedException e ){                               e.printStackTrace() ;                        }                         synchronized (zs ){                         ls .get() ;                        }                  }            }      }public static void main(String args[]){      ThreadDeadLock t1 = new ThreadDeadLock() ; // 控制张三      ThreadDeadLock t2 = new ThreadDeadLock() ; // 控制李四       t1. flag = true ;       t2. flag = false ;      Thread thA = new Thread( t1) ;      Thread thB = new Thread( t2) ;       //两个线程启动,各自调用run方法,这样的话各自需要的资源被占用,死锁发生
       thA .start() ;       thB .start() ;      }}

声明:此文参考了很多博文,包括书籍,因为比较杂,本人已经记不住出处了,所以有些引用就不注明出处了,还请见谅。

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



Java基础(九)——多线程 Java多线程基础 Java多线程基础 Java基础:多线程 java基础-多线程 Java多线程基础 Java多线程基础 Java多线程-基础 java 多线程基础 【Java基础】——多线程
 
粤ICP备14056181号  © 2014-2020 ITdaan.com