java学习之路---线程(重点)

来源:互联网 发布:现货农产品分析软件 编辑:程序博客网 时间:2024/06/05 08:18
 1.多线程是一种并发机制的有效手段。进程和线程一样,都是实现并发的一个基本单位。线程是比进程更小的一种实现单位,线程是在进程的基础上的进一步划分。所谓的多线就是在一个进程中产生了多个线程,这些线程可以同时存在,同时运行。
2.多线程的实现

          1.继承Thread类
          2.实现runnable接口


3.继承Thread类
public class ThreadDemo extends Thread{
     private String userName;
     
          
     
     public String getUserName() {
           return userName ;
     }

     public void setUserName(String userName) {
           this.userName = userName;
     }

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

     @Override
     public void run() {
           for(int i=1;i<10;i++){
             System.out.println( userName+i);
          }
     }

     public static void main(String[] args) {
           ThreadDemo threadDemo=new ThreadDemo ("线程A" );
           ThreadDemo threadDemo1=new ThreadDemo ("线程B" );
          threadDemo.run();
          threadDemo1.run();
     }

}

结果:
线程A1
线程A2
线程A3
线程A4
线程A5
线程A6
线程A7
线程A8
线程A9
线程B1
线程B2
线程B3
线程B4
线程B5
线程B6
线程B7
线程B8
线程B9

发现并没有实现多线程,如果要正确的启动多线程,则要调用start方法。

代码:
public class ThreadDemo extends Thread{
     private String userName;
     
          
     
     public String getUserName() {
           return userName ;
     }

     public void setUserName(String userName) {
           this.userName = userName;
     }

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

     @Override
     public void run() {
           for(int i=1;i<10;i++){
              System. out.println(userName +i);
          }
     }

     public static void main(String[] args) {
           ThreadDemo threadDemo=new ThreadDemo ("线程A" );
           ThreadDemo threadDemo1=new ThreadDemo ("线程B" );
          threadDemo.start();
          threadDemo1.start();
     }

}

结果(这只是其中的一种):
线程A1
线程B1
线程A2
线程B2
线程A3
线程B3
线程A4
线程A5
线程A6
线程A7
线程B4
线程A8
线程A9
线程B5
线程B6
线程B7
线程B8
线程B9

为什么要调用start,而不是调用run方法喃?
看源码:
 public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add( this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed( this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    private native void start0();

返现这里的start0()用了 native ,这个关键字表示调用本机的操作系统函数,因为多线程需要底层操作系统的支持。



如果一个类继承了Thread类,那么一个对象就只能调用一次,如果调用多次,则会抛出异常

public class ThreadDemo extends Thread{
     private String userName;
     
          
     
     public String getUserName() {
           return userName ;
     }

     public void setUserName(String userName) {
           this.userName = userName;
     }

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

     @Override
     public void run() {
           for(int i=1;i<10;i++){
              System. out.println(userName +i);
          }
     }

     public static void main(String[] args) {
          ThreadDemo threadDemo= new ThreadDemo("线程A" );
          ThreadDemo threadDemo1=new ThreadDemo( "线程B");
          threadDemo.start();
          threadDemo.start();
     }

}
结果:
线程A1
线程A2
线程A3
线程A4
线程A5
线程A6
线程A7
Exception in thread "main" java.lang.IllegalThreadStateException
     at java.lang.Thread.start( Thread.java:682)
     at test.ThreadDemo.main( ThreadDemo.java:34)
线程A8
线程A9

所以如果一个类继承Thread类,想要实现多线程,就有单继承的局限性,所以最好实现runnable接口

4.实现runnable 接口

class MyTread implements Runnable{
     private  Integer  ticket=10;
     public void run() {
          
          fun();
     }
     
     public synchronized void fun(){
           for(int i=0;i<100;i++){
              
               if(ticket >0){
                   System. out.println("卖票: ticket="+ticket--);
                   
              }
     
          
     }
     }
};

public class ThreadDemo1{
           public static void main(String[] args) {
              MyTread myTread= new MyTread();
               new Thread(myTread).start();
               new Thread(myTread).start();
               new Thread(myTread).start();
          }
     
}

这样写:
可以实现多线程的访问(下面的结果是因为锁的原因)

结果:
卖票: ticket=10
卖票: ticket=9
卖票: ticket=8
卖票: ticket=7
卖票: ticket=6
卖票: ticket=5
卖票: ticket=4
卖票: ticket=3
卖票: ticket=2
卖票: ticket=1

如果代码改为这样:

class MyTread implements Runnable{
     private  Integer  ticket=10;
     public void run() {
           for(int i=0;i<100;i++){
               if(ticket >0)
              System. out.println("票号" +ticket --);
              
          }
          
          
     }
     
}
public class ThreadDemo1{
           public static void main(String[] args) {
              MyTread myTread= new MyTread();
               new Thread(myTread).start();
               new Thread(myTread).start();
               new Thread(myTread).start();
          }
     
}
结果:(不唯一)

票号10
票号8
票号9
票号6
票号4
票号3
票号2
票号1
票号7
票号5


5.线程的状态

     线程有五种状态

                         
创建状态:一个线程被创建后就处于创建状态,此时它拥有了相应的内存空间和其他资源,但是还处于不可运行状态

就绪状态:当调用线程的时候就进入就绪状态,此时,它将进入线程队列排队,等待CPU服务。

运行状态:CPU调用该资源,自动调用该线程对象的run方法

阻塞状态:CPU暂时中止此线程的进行。

死亡:线程调用stop()或者run()方法运行完成后


6.线程的相关方法




应用方法代码:

          取得线程名称:

class MyTread implements Runnable{
      private  Integer  ticket=10;
      public void run() {
           for (int i=0;i<100;i++){
               if (ticket >0)
               System. out .println(Thread.currentThread().getName()+ "票号" +ticket -- );//取得线程名称,如果自己没有给名称,那么程序就会自动付给一个名称

看源码:


    public Thread (Runnable target) {
        init( null , target, "Thread-" nextThreadNum(), 0);
    }

  private static synchronized int nextThreadNum () {
        return threadInitNumber ++;
    }


              
          }
          
          
     }
     
}
public class ThreadDemo1 {
           public static void main(String[] args) {
              MyTread myTread= new MyTread();
               new Thread(myTread).start();
               new Thread(myTread).start();
               new Thread(myTread).start();
          }
     
}
结果:

Thread-1票号10
Thread-0票号9
Thread-1票号8
Thread-2票号6
Thread-0票号7
Thread-2票号4
Thread-1票号5
Thread-2票号2
Thread-0票号3
Thread-1票号1

如果给了名称:

class MyTread implements Runnable{
      private  Integer  ticket=10;
      public void run() {
           for (int i=0;i<100;i++){
               if (ticket >0)
               System. out .println(Thread.currentThread().getName()+ "票号" +ticket -- );
              
          }
          
          
     }
     
}
public class ThreadDemo1 {
           public static void main(String[] args) {
              MyTread myTread= new MyTread();
              
               new Thread(myTread,"A线程" ).start(); //自己给线程名称
               new Thread(myTread,"like" ).start();
               new Thread(myTread).start();
          }
     
}
结果:

like票号10
like票号9
like票号7
like票号6
A线程票号8
Thread-0票号4
like票号5
Thread-0票号2
A线程票号3
like票号1

补充:

java程序启动的时候至少启动两个程序,一个是:main,一个是垃圾回收机制



线程的休眠:

class MyTread implements Runnable{
      private  Integer  ticket=10;
      public void run() {
           for (int i=0;i<100;i++){
               if (ticket >0){
                    try {
                        Thread. sleep(1000);//这里休眠1000ms==1S
                   } catch (InterruptedException e) {
                        
                        e.printStackTrace();
                   }
               System. out .println(Thread.currentThread().getName()+ "票号" +ticket -- );
              }
              
          }
          
          
     }
     
}
public class ThreadDemo1 {
           public static void main(String[] args) {
              MyTread myTread= new MyTread();
              
               new Thread(myTread,"A线程" ).start(); //自己给线程名称
               new Thread(myTread,"like" ).start();
               new Thread(myTread).start();
          }
     
}

自己打印结果的时候:就会发现有停顿:

like票号10
A线程票号10
Thread-0票号9
like票号8
A线程票号7
Thread-0票号6
like票号5
A线程票号4
Thread-0票号3
like票号2
A线程票号2
Thread-0票号1
like票号0
A线程票号-1

这里出现了-1,是因为在if(ticket>0)判断的时候,上一个线程还没有ticket -- ,而另一个线程就已经进入





判断线程是否启动:

class MyTread implements Runnable{
      private  Integer  ticket=10;
      public void run() {
           for (int i=0;i<100;i++){
               if (ticket >0){
                    try {
                        Thread. sleep(1000);
                   } catch (InterruptedException e) {
                        
                        e.printStackTrace();
                   }
               System. out .println(Thread. currentThread().getName()+ "票号"+ ticket-- );
              }
              
          }
          
          
     }
     
}
public class ThreadDemo2 {
     
      public static void main(String[] args) {
          MyTread myTread= new MyTread();
          
     Thread t=  new Thread(myTread,"A线程" );//自己给线程名称
     System. out.println ("线程是否启动" +t.isAlive());
     
     t.start(); //启动线程
     
     System. out.println ("线程是否启动" +t.isAlive());
           new Thread(myTread,"like" ).start();
           new Thread(myTread).start();
     }

结果:

线程是否启动false
线程是否启动true
like票号10
A线程票号10
Thread-0票号9
A线程票号8
like票号7
Thread-0票号6
A线程票号5
like票号4
Thread-0票号3
A线程票号2
like票号1
Thread-0票号0
A线程票号-1


线程的强制进行:

class MyTread implements Runnable{
      private  Integer  ticket=10;
      public void run() {
           for (int i=0;i<100;i++){
               if (ticket >0){
                    try {
                        Thread. sleep(1000);
                   } catch (InterruptedException e) {
                        
                        e.printStackTrace();
                   }
               System. out .println(Thread.currentThread().getName()+ "票号" +ticket -- );
              }
              
          }
          
          
     }
     
}
public class ThreadDemo2 {
     
      public static void main(String[] args) {
          MyTread myTread= new MyTread();
          
     Thread t=  new Thread(myTread,"A线程" );//自己给线程名称
     System. out.println( "线程是否启动" +t.isAlive());
     
     t.start(); //启动线程
     
      for( int i=0;i<10;i++){
           if (i>2){
               try {
                   t.join(); //线程的强制惊醒
              } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                   e.printStackTrace();
              }
          }
     }
     System. out.println( "线程是否启动" +t.isAlive());
           new Thread(myTread,"like" ).start();
           new Thread(myTread).start();
          
          
     }

}

结果:

线程是否启动false
A线程票号10
A线程票号9
A线程票号8
A线程票号7
A线程票号6
A线程票号5
A线程票号4
A线程票号3
A线程票号2
A线程票号1
线程是否启动false

为什么第二次判断也是false,那是因为,线程A已经执行完毕,所以已经死亡,自然是false


线程的中止:
class MyTread1 implements Runnable{
      private  Integer  ticket=10;
      public void run() {
           for (int i=0;i<100;i++){
               if (ticket >0){
                    try {
                        Thread. sleep(3000);
                   } catch (InterruptedException e) {
                        System. out .println("A线程被中止" );
                         return ;
                   }
               System. out .println(Thread.currentThread().getName()+ "票号" +ticket -- );
              }
              
          }
          
          
     }
     
}
public class ThreadDemo2 {
     
      public static void main(String[] args) {
          MyTread1 myTread= new MyTread1();
          
     Thread t=  new Thread(myTread,"A线程" );//自己给线程名称
     System. out.println( "线程是否启动" +t.isAlive());
     
     t.start(); //启动线程
      try {
          Thread. sleep(2000);
     } catch (InterruptedException e) {
           // TODO Auto-generated catch block
          e.printStackTrace();
     }
     
     t.interrupt();
     
     System. out.println( "线程是否启动" +t.isAlive());
           new Thread(myTread,"like" ).start();
           new Thread(myTread).start();
          
          
     }

}
结果:
线程是否启动false
线程是否启动true
A线程被中止
like票号10
Thread-0票号9
like票号8
Thread-0票号7
like票号6
Thread-0票号5
like票号4
Thread-0票号3
like票号2
Thread-0票号1



后台线程:

t.setDaemon( true);



7.线程的优先级

class MyTread1 implements Runnable{
      private  Integer  ticket=10;
      public void run() {
           for (int i=0;i<100;i++){
               if (ticket >0){
                    try {
                        Thread. sleep(100);
                   } catch (InterruptedException e) {
                        System. out .println("A线程被中止" );
                   }
               System. out .println(Thread.currentThread().getName()+ "票号" +ticket -- );
              }
              
          }
          
          
     }
     
}
public class ThreadDemo2 {
     
      public static void main(String[] args) {
          MyTread1 myTread= new MyTread1();
          
     Thread t=  new Thread(myTread,"A线程" );//自己给线程名称
     
     Thread t1=     new Thread(myTread,"like" );
     Thread t2=     new Thread(myTread);
     
          t.setPriority(Thread. MAX_PRIORITY );//设置线程优先级,最大10
          t1.setPriority(Thread. MIN_PRIORITY );最小1
          t2.setPriority(Thread. NORM_PRIORITY );5
     
          
          t1.start();
          t.start(); //启动线程
          t2.start();
          
     }

}

结果:
like票号10
A线程票号8
Thread-0票号9
Thread-0票号7
like票号6
A线程票号5
Thread-0票号4
like票号3
A线程票号2
Thread-0票号1
A线程票号0
like票号-1

这说明不是绝对那个线程的优先级高,就调用那个,而是要看CPU的调度



public class ThreadDemo2 {
     
      public static void main(String[] args) {
//        MyTread1 myTread=new MyTread1();
//        
//   Thread t= new Thread(myTread,"A线程");//自己给线程名称
//   
//   Thread t1=    new Thread(myTread,"like");
//   Thread t2=    new Thread(myTread);
//   
//        t.setPriority(Thread.MAX_PRIORITY);//设置线程优先级
//        t1.setPriority(Thread.MIN_PRIORITY);
//        t2.setPriority(Thread.NORM_PRIORITY);
//   
//        
//        t1.start();
//        t.start();//启动线程
//        t2.start();
          
          System. out .println(Thread.currentThread().getPriority()); //获取主方法的优先级
          
     }

}

结果:
5


8.线程的礼让:(让当前的线程暂时让个其他线程)

class MyTread1 implements Runnable{
      private  Integer  ticket=10;
      public void run() {
           for (int i=0;i<100;i++){
               if (ticket >0){
                   System. out .println(Thread.currentThread().getName()+ "----->" );//获取线程的名字
                    if (ticket ==3){
                        System. out .print("线程礼让:" );
                         Thread.currentThread ().yield();
                   }
               System. out .println(Thread.currentThread().getName()+ "票号" +ticket -- );
              }
              
          }
          
          
     }
     
}
public class ThreadDemo2 {
     
      public static void main(String[] args) {
          MyTread1 myTread= new MyTread1();
          
     Thread t=  new Thread(myTread,"A线程" );//自己给线程名称
     
     Thread t1=     new Thread(myTread,"like" );
     Thread t2=     new Thread(myTread);
     
          t.setPriority(Thread. MAX_PRIORITY );//设置线程优先级
          t1.setPriority(Thread. MIN_PRIORITY );
          t2.setPriority(Thread. NORM_PRIORITY );
          t1.start();
          t.start(); //启动线程
          t2.start();
          
     }

}

结果:
A线程----->
like----->
Thread-0----->
Thread-0票号8
A线程票号10
like票号9
Thread-0----->
like----->
A线程----->
A线程票号5
like票号6
like----->
like票号4
like----->
线程礼让:like票号3
like----->
like票号2
like----->
like票号1
Thread-0票号7
A线程----->
A线程票号0

看看结果:当线程like让出当前线程,但是下一个执行的线程还是like线程,这说明线程的礼让不是绝对的,不是礼让了就一定会让给其他线程