线程技术初窥

线程技术初窥

 

1. 程的生命周期(仔细看图)

     
线程技术初窥

 

2.  main线程以及继承Thread实现多线程:

        虽然多线程看起来像同时进行,但事实上在同一时间点上只有一个线程被执行,只是线程间切换较快,所以才会使人产生线程是同时进行的假象。
       Therad类的currentThread()方法可以获取当前线程并输出该线程的名称。
       代码如下:

 

public class MainThread {

      public static void main(String[] args) {
            System.out.println("main 主方法开始运行");
            Thread currentThread =Thread.currentThread();
            System.out.println("获取当前线程对象");
            String name =currentThread.getName();
            System.out.println("当前线程名称是:"+name);
      }

}
    Thread类是java语言的线程类,它位于java.lang包中。
    建立多线程需要重写run()方法:
public class Writer extends Thread {

      private String name;

      public Writer(String name) {
            this.name = name;
      }

      public void run() {
            while (true) {
                  System.out.println(name);
                  try {
                        Thread.sleep((int)(Math.random()*10000));
                  } catch (Exception e) {
                  }
            }
      }

      public static void main(String[] args) {
            Thread writer1=new Writer("作者1");
            Thread writer2=new Writer("作者2");
            writer1.start();
            writer2.start();
      }

}
    创建线程的另一种方法是声明实现 Runnable 接口的类。
public class Writer implements Runnable {
    long minPrime;
    Writer(long minPrime) {
          this.minPrime = minPrime;
    }

    public void run() {
    }

      public static void main(String[] args) {
            Writer writer1 = new Writer(123);
           new Thread(writer1).start();
      }

}
    启动一个新的线程,不是直接调用Thread类的run()方法,而是调用Thread子类的start()方法。
    Thread类的start()方法会产生一个新的线程,该线程运行Thread子类的run()方法。

 

3.  线程的休眠:

      sleep()方法.

try {
                  Thread.sleep(2000);
            } catch (Exception e) {

            }
   表示线程在2000毫秒内不会进入就绪状态,也就是暂停两秒。

4.  线程停止:

       早期版本里用stop()方法停止线程,但是新版本里废除了stop()方法。现在提倡在run()方法中使用布尔型标记控制循环停止。
      例:在项目中创建InterruptedTest类,该类继承了Runnable方法,设置线程正确停止方式。

 

public class InterruptedTest implements Runnable {
      private boolean isContinue = true;

      @Override
      public void run() {
            while (true) {
                  if (isContinue)
                        break;
            }

      }

      public void setContinue() {
            this.isContinue = true;
      }

}
    如果线程因为是使用了sleep()或wait()方法进入了就绪状态,可以使用interrupt()方法使线程离开run()方法,同时结束线程,但程序会抛出InterruptedException异常。

 

5.  线程调度:

        当某个线程使用join()方法加入到另一个线程时,另一个线程会等待该线程执行完毕再继续执行。
      实例:

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JProgressBar;

/**
 * 线程调度的实例
 * @author 李钟尉
 */
public class JoinMain extends JFrame {
      private Thread threadA; // 线程A
      private Thread threadB; // 线程B
      private Thread threadC; // 线程B
      final JProgressBar progressBarA = new JProgressBar(); // 进度条A
      final JProgressBar progressBarB = new JProgressBar(); // 进度条B
      final JProgressBar progressBarC = new JProgressBar(); // 进度条C
      public static void main(String[] args) {
            new JoinMain();
      }
      
      /**
       * 构造方法
       */
      public JoinMain() {
            super();
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setSize(200, 100);
            setVisible(true);
            getContentPane().add(progressBarA, BorderLayout.NORTH);
            getContentPane().add(progressBarB);
            getContentPane().add(progressBarC, BorderLayout.SOUTH);
            progressBarA.setStringPainted(true);
            progressBarA.setString("线程A");
            progressBarB.setStringPainted(true);
            progressBarB.setString("线程B");
            progressBarC.setStringPainted(true);
            progressBarC.setString("线程C");
            
            // 创建线程A
            threadA = new Thread(new Runnable() {
                  public void run() {
                        for (int i = 0; i <= 100; i++) {
                              progressBarA.setValue(i);
                              progressBarA.setString("线程A   " + i + "%");
                              try {
                                    Thread.sleep(100); // 休眠0.1秒
                              } catch (Exception e) {
                                    e.printStackTrace();
                              }
                        }
                  }
            });
            // 创建线程B
            threadB = new Thread(new Runnable() {
                  public void run() {
                        for (int i = 0; i <= 100; i++) {
                              progressBarB.setValue(i);
                              progressBarB.setString("线程B   " + i + "%");
                              try {
                                    Thread.sleep(100);
                              } catch (Exception e) {
                                    e.printStackTrace();
                              }
                        }
                  }
            });
            // 创建线程C
            threadC = new Thread() {
                  public void run() {
                        for (int i = 0; i <= 100; i++) {
                              progressBarC.setValue(i);
                              progressBarC.setString("线程C   " + i + "%");
                              try {
                                    Thread.sleep(100);
                              } catch (Exception e) {
                                    e.printStackTrace();
                              }
                        }
                  }
            };
            try {
                  threadA.start(); // 启动线程A
                  threadA.join();
                  threadB.start(); // 启动线程B
                  threadB.join();
                  threadC.start(); // 启动线程B
                  threadC.join();
            } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
            }
      }
}
 

 

6.  设置线程优先级:

      Thread 有优先级,比如
      MAX_PRIORITY  线程可以具有的最高优先级。
      MIN_PRIORITY  线程可以具有的最低优先级。
      NORM_PRIORITY 分配给线程的默认优先级。
      线程优先级可以通过setPriority()方法调整,优先级必须在1-10之内,否则将产生异常。

 

7.  线程同步问题:

       在多线程编程中,必须防止资源的冲突。Java提供线程同步的机制可以防止资源访问的冲突.
      线程的同步机制:
      如何解决资源共享问题,通常是允许一个线程访问共享资源,这时就给共享资源加把锁。
      1.同步块:
       java同步机制中采用synchronized关键字。它的语法结构如下:

            synchronized (object) {
                  //业务代码
            }
    模拟火车站售票系统:
/**
 * 本实例演示多个线程同时访问一个公有资源的安全问题
 */
public class ThreadSafeTest extends Thread {
      private static Integer num = 1;                                   // 剩余票数(共享资源)
      
      /**
       * 构造方法
       * @param name 线程的名称,本实例对应售票员名称
       */
      public ThreadSafeTest(String name) {
            setName(name);                                                    // 设置线程名
      }
      /**
       * 线程核心方法
       */
      @Override
      public void run() {
            synchronized (num) {
                  if (num > 0) { // 检查剩余票数
                        System.out.println(getName() + ":检测票数大于0");
                        System.out.println(getName() + ":\t正在收款(大约5秒完成)……");
                        try {
                              Thread.sleep(5000); // 5秒收款时间
                              System.out.println(getName() + ":\t打印票据,售票完成");
                              num--;
                              printNumInfo(); // 输出车票状况信息
                        } catch (InterruptedException e) {
                              e.printStackTrace();
                        }
                  }
                  else {
                        System.out.println("没有票了,停止出售");
                  }
            }
      }
      /**
       * 输出车票状况信息的方法,该方法输出当前剩余票数,如果低于0则输出经过信息
       */
      private void printNumInfo() {
            System.out.println("系统:当前剩余票数:" + num);
            if(num<0){                                                        // 如果剩余票数呈现负数
                  System.out.println("警告:票数低于0,出现负数");
            }
      }
      
      /**
       * @param args
       */
      public static void main(String[] args) {
            try {
                  new ThreadSafeTest("售票员李某").start(); // 启动第一个线程
                  Thread.sleep(2000);                                         // 两秒后
                  new ThreadSafeTest("售票员王某").start(); // 启动第二个线程
            } catch (InterruptedException e) {
                  e.printStackTrace();
            }
      }
}
 
  显示结果:
  售票员李某:检测票数大于0
  售票员李某:      正在收款(大约5秒完成)……
  售票员李某:      打印票据,售票完成
  系统:当前剩余票数:0
  没有票了,停止出售
    2.同步方法:
    同步方法是在方法前面修饰synchronized关键字的方法,它的语法如下
   
    synchronized  void syncMethod() {
        //业务代码
  }
    当某个对象调用同步方法时,其它方法必须等待该同步方法执行完毕才能被执行。所有将每个能访问共享资源的方法修饰为synchronized可以防止多个线程同时修改或访问共享资源。
    还是上面的例子:
public class ThreadSafeTest extends Thread {
	private static int num = 1; // 剩余票数
	
	/**
	 * 构造方法
	 * @param name 线程的名称,本实例对应售票员名称
	 */
	public ThreadSafeTest(String name) {
		setName(name);										// 设置线程名称
	}
	/**
	 * 线程核心方法
	 */
	@Override
	public void run() {
		sell(getName());									// 执行售票方法
	}
	/**
	 * 销售车票的方法,该方法是线程安全的。
	 * @param name 售票员名称
	 */
	private static synchronized void sell(String name) {
		System.out.println(name+":开始售票,正在查询票数……");
		if (num > 0) {
			System.out.println(name + ":检测票数大于0");
			System.out.println(name + ":\t正在收款(大约5秒完成)……");
			try {
				Thread.sleep(5000);
				System.out.println(name + ":\t打印票据,售票完成");
				num--;
				printNumInfo();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else{
			System.out.println(name + ":\t没有票了,停止出售");
		}
	}
	/**
	 * 输出车票库存情况的方法,如果库存为负数,输出警告信息
	 */
	private static void printNumInfo() {
		System.out.println("系统:当前剩余票数:" + num);
		if(num<0){
			System.out.println("警告:票数低于0,出现负数");
		}
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			new ThreadSafeTest("售票员李某").start();
			Thread.sleep(2000);
			new ThreadSafeTest("售票员王某").start();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}