Java基础之--多线程

来源:互联网 发布:淘宝6s官换机是真的吗 编辑:程序博客网 时间:2024/06/06 02:18
多线程(multitherading['mʌltɪ'θredɪŋ]):多条分支同时进行。是指从软件或者硬件实现多个线程并发的技术。
具有多线程能力的计算机因有硬件的支持能够在同一时间执行多于一个线程,进而提升整体处理性能。(具有这种能力的系统包括对称处理机、多核心处理器等)
在一个程序中,这些独立运行的程序片段叫做线程(thread)。

Java实现多线程两种方式:

1、继承Thread类
让一个类继承Thread类,并重写父类的run方法(注意:要用start()方法启动,而不是run()函数调用) 

package testTread;
/**
 * 多线程--继承Tread类
 * @author Super
 */
public class Test {
       public static void main(String[] args) {
              new Test().getFirstThrade();
              for (int i = 0; i < 5; i++) {
                   System.out.println("main" + i);
                   }

          }

        public void getFirstThrade() {
               FirstThrade mt = new FirstThrade();
               mt.start();
          }

        class FirstThradeextends Thread {
              @Override
              public void run() {
                     for(int i = 0; i < 5; i++) {
                          System.out.println("first" + i);
                     }
              }
        }
}

2、实现Runnable接口(因为Java中不支持多继承,所以用实现Runnale接口方式实现多线程)
让一个类实现Runnable,并实现接口中的run方法,由于接口中没有start方法,所以需要将其放置到一个Thread类中运行

package testTread;

/**

 * 多线程--实现runnable接口

 * @author Super

 */

public class Test01 {

       public static void main(String[] args) {

              new Test01().begin();

       }
       public void begin(){

              FirstRunnable fr = new FirstRunnable();

              Thread thread = new Thread(fr);

              thread.start();

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

                  System.out.println("begin"+i);

              }

          }

       class FirstRunnable implements  Runnable {

             public void run() {

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

                        System.out.println("firstRunnable"+i);

                    }

             }

       }

}

多线程的调度:


Thread.sleep() --->Blocked(休眠)状态。时间结束后才回到Runnable(等待状态)
Join()--->一直不轮换 一直Running状态(执行)到结束。
static yield() --->结束执行状态到runnable状态(立即进入等待状态,并且不参与本次竞争)。让当前的线程暂时停止,让给其他的线程(单核有效CUP,多核CPU无效)
isAlive()---->判断当前线程是否处于活动状态(即调用start方法后到执行完毕前的状态)
getId()--->取得现成的唯一标识



在Thread类中,其中两个构造函数"Thread(Runnable target)"、"Thread(Runnable target,String name)"可以传递Runnable接口,所以构造函数支持传入一个Runnable接口的对象。

非线程安全的意思是:多个线程对同一个对象中的同一个变量进行操作。
注释:方法内的变量为线程安全,如果该变量(成员变量)是属于类的,则该实例变量非线程安全。

package testTread;
/**
 * 线程是否安全
 * @author Super
 */
public class Test02 {
     public static void main(String[] args){
          new Test02().begin();
    }
     //线程间不共享实例变量
     /*public void begin(){
            MyThread mt1 = new MyThread("1");
            MyThread mt2 = new MyThread("2");
            MyThread mt3 = new MyThread("3");
            MyThread mt4 = new MyThread("4");
            MyThread mt5 = new MyThread("5");
            mt1.start();
            mt2.start();
            mt3.start();
            mt4.start();
            mt5.start();
       }*/
      //线程安全的共享实例变量
      public void begin(){
          MyThread mt = new MyThread("MyThread");
          Thread thread1 =new Thread(mt, "1");
          Thread thread2 =new Thread(mt, "2");
          Thread thread3 =new Thread(mt, "3");
          Thread thread4 =new Thread(mt, "4");
          Thread thread5 =new Thread(mt, "5");
                 thread1.start();
                 thread2.start();
                 thread3.start();
                 thread4.start();
                 thread5.start();
      }
      class MyThreadextends Thread{
           int count=5;
           public MyThread(String name) {
                super(name);
           }
           @Override
           synchronized public void run() {
                count--;
                System.out.println(Thread.currentThread().getName()+"线程操作的:"+count);
           }
     }
}
注释:
Thread.currentThread()--该方法是获取当前线程

Thread.stop()--->停止线程(已经弃用了,因为不是安全的(没有释放资源),现在一般用新建boolean变量方法,判断true和false,用for+break跳出的方式)
在Java中有三种终止正在运行线程的方法:
1、使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
2、使用stop方法强行终止线程,但不推荐使用这个方法,因为stop和suspend及resume一样,都是作废过期的方法,使用它们可能会产生不可预料的结果。
      调用stop方法会抛出java.lang.ThreadDeath异常,一般情况下,次异常不需要显式捕捉。
      使用stop()方法已经作废,如果强制让线程停止则有可能使一些清理性的工作不能完成,另外一个情况是对锁定的对象进行“解锁”,导致数据得不到同步处理。
  

packagetest;
/**
 * 用stop()方法停止线程,造成释放对象锁后造成的结果不一致
 * @author 丑逼
 */
public classTest08 {
     public static voidmain(String[] args) {
          newTest08().begin();
     }
     public voidbegin(){
          try{
              SynchronizedObject so =new SynchronizedObject();
              MyRunnable mr =new MyRunnable(so);
              Thread tmr =new Thread(mr);
              tmr.start();
              Thread.sleep(50);//睡眠50毫秒,这样能保证执行trm中的run()方法后在stop()或者说当执行MyRunnable线程的start()方法后,main线程睡眠50毫秒
              tmr.stop();
               System.out.println("userName:"+so.getUserName()+"  password:"+so.getPassword());
          }catch (InterruptedException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
     }
     classSynchronizedObject {
          privateString userName="aaa";
          privateString password="aaa";

          publicString getUserName() {
              returnuserName;
          }

          public voidsetUserName(String userName) {
              this.userName= userName;
          }

          publicString getPassword() {
              returnpassword;
          }

          public voidsetPassword(String password) {
              this.password= password;
          }

          synchronized public voidprintString(String userName, String password) {
              try{
                   this.userName= userName;
                   Thread.sleep(1000);//当run()方法给userName赋值后睡眠1000毫秒(1秒),把机会让给main线程,这样似的password没有被赋值的情况下停止线程
                   this.password= password;
              }catch (Exception e) {

              }
          }

     }
     classMyRunnable implements Runnable{
          privateSynchronizedObject obj;
          publicMyRunnable(SynchronizedObject obj) {
              this.obj= obj;
          }
          public voidrun() {
              obj.printString("bbb","bbb");//run()方法给SunchronizedObject类的userName和password赋值
          }

     }
}




3、使用interrupt方法中断线程。
     interrupt()方法使用效果不像for+break语句马上停止循环。而是仅仅在当前线程中搭了一个暂停标记,并不是真的停止线程。
判断线程是否是停止状态:
1、this.interrupted()--->测试当前线程是否已经中断。
     测试当前线程是否已经中断状态,执行后具有将状态标识清除为false的功能。
2、this.isInterrupted()--->测试线程是否已经中断。
     测试线程Thread对象是否已经中断状态,但不清除状态标志。

能停止的线程---异常法

package testTread;
/**
 * 线程的停止系列之--异常法[借助interrupt(打断、暂停)]
 * @author Super
 */
public class Test09 {
          public static void main(String[] args) {
                   new Test09().begin();
          }

          public void begin() {
                   try {
                        MyThread mr = new MyThread();
                        mr.start();
                        Thread.sleep(20);
                        mr.interrupt();
                   } catch (Exception e) {
                   }
                   System.out.println("end!");
          }
          class MyThread extends Thread {
                   int index = 0;
                   public void run() {
                          try{
                             for (; index < 5000; index++) {
                                      if(this.isInterrupted()){
                                              System.out.println("已经是停止状态了!我要退出了!");
                                              throw new InterruptedException ();
                                      }
                                      System.out.println("index=" + index);
                             }
                             System.out.println("我被输出了,如果此代码是for又继续运行");
                          }catch(InterruptedException  e ){
                             System.out.println("进入MyThread.java类run方法中的catch了!");
                          }
                   }

          }
}



能停止的线程---在沉睡中停止


线程同步:
关键字:synchronized
可以在对象及方法上添加synchronized,而加了synchronized的代码称为:"互斥区"或"临界区"。
同步会丢失效率!!!因为一个对象操作的时候,其他线程的对象只能等着。
什么时候使用同步(synchronized):两个或两个以上的线程同时修改一个变量。
非线程安全:多个(两个或两个以上)线程对同一个对象中的实例变量操作时会出现值被修改、值不同步,进而影响程序的执行流程。

死锁:
synchronized嵌套容易出现死锁!(避免死锁的最佳方式是:1、不要出现同步的嵌套。2、让同步块尽可能的大(效率会降低))


package testTread;
/**
 * 死锁
 * @author Super
 */
public class Test06 {
       public static void main(String[] args) {
              new Test06().begin();
       }
       public void begin(){
              Deadlock deadlock = new Deadlock();
              Thread t1 = new Thread(deadlock, "石小渣");
              Thread t2 = new Thread(deadlock, "张梦怼");
              t1.start();
              t2.start();
        }
   // 有两个或两个以上需要同步的代码块不能使用this作为钥匙
   class Deadlock implements Runnable {
      private Object o1 = new Object();// 第一把钥匙
      private Object o2 = new Object();// 第二把钥匙
      private boolean flag = true;// 标识

      public void run() {
             if (flag) {
                 flag = false;
                 synchronized (o1) {
                       System.out.println(Thread.currentThread().getName() + "拿到第一把钥匙!");
                              try {
                                    System.out.println(Thread.currentThread().getName() + "睡觉去啦!");
                                    Thread.sleep(100);
                              } catch (InterruptedException e) {
                                    e.printStackTrace();
                              }
                               synchronized (o2) {
                                     System.out.println((Thread.currentThread().getName() + "拿到第二把钥匙!"));
                                                }
                                      }
             } else {
                 flag = true;
                 synchronized (o2) {
                        System.out.println(Thread.currentThread().getName() + "拿到第二把钥匙!");
                        try {
                              System.out.println(Thread.currentThread().getName() + "睡觉去啦!");
                              Thread.sleep(100);
                        } catch (InterruptedException e) {
                              e.printStackTrace();
                        }
                              synchronized (o1) {
                                        System.out.println(Thread.currentThread().getName() + "拿到第一把钥匙!");
                              }
                  }
            }
      }

   }
}




生产者和消费者:主要是用在线程间切换的。
wait:挂起线程
notify:唤醒线程(随机唤醒挂起的线程)
notifyAll:如果使用notifyAll,这个obj必须是同步块里的钥匙。


线程的优先级:
设置线程的优先级可以使用setPriority()方法,线程的优先级分为1~10,如果小于1或大于10则抛出异常
优先级具有继承的特性,例如用A线程启动B线程,则B线程的优先级与A相同。
优先级具有随机性,线程优先级较高的可能优先执行完run(),但并不是优先级高每次都先执行完。
线程的暂停:
     1、suspend()方法暂停
     2、resume()方法恢复线程执行
     使用suspend与resume方法的缺点:独占、不同步
    如果使用不当,极易造成公共的同步对象的独占,使得其他线程无法访问公共同步对象.
     
守护线程(后台线程):setDaemon(true)
      java有两种线程:1、用户线程 2、守护线程
      守护线程是一种特殊的线程,当进程中不存在非守护线程,则守护线程自动销毁。(典型的守护线程就是垃圾回收线程)

volatile关键字:
      主要作用是使变量在多个线程间可见。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
原创粉丝点击