在Java中要想实现多线程的程序,必须依靠一个线程的主体类,即主线程(执行主方法(main)的线程)。然后此类继承Thread类或实现Runnable接口。
java.lang.Thread是操作线程的类,任何类只需要继承Thread类就可以成为一个线程的主类。 Thread类下的两个重要方法: run()和start()方法。 线程执行体:run()。(线程需要完成的任务) 线程的起点:start()。(线程的启动,启动后执行的方法体是run()方法定义的代码) 程序的起点:main()。
实例:
//1.创建一个Thread类的子类 public class MyThread extends Thread{ //2.重写Thread类中的run方法,设置线程任务 @Override public void run(){ for (int i = 0; i < 20; i++) { System.out.println("run:"+i); } } } public class doMain { public static void main(String[] args) { //3.创建Thread类的子类对象 MyThread mt = new MyThread(); //4.调用Thread类中的start(),开启新的线程,执行run() mt.start(); for (int i = 0; i < 20; i++) { System.out.println("main:"+i); } } }Thread类的常用方法: getName() :取得线程名字 setName() :设置线程名字 currentThread() :取得线程名字 sleep(long millitime) :使当前正在执行的程序以指定的毫秒数暂定
为了避免单继承局限的问题,我们可以使用Runnable接口来实现多线程。 要启动多线程,就一定需要通过Thread类中的start()方法,但是Runnable接口中没有提供可以被继承的start()方法。这时就需要借住Thread类中提供的有参构造方法:
public Thread(Runnable target)此方法可以接收一个Runnable接口对象实例:
public static void main(String[] args) { // TODO Auto-generated method stub MyThread2 m=new MyThread2(); new Thread(m).start(); new Thread(m).start(); } class MyThread2 implements Runnable{ private int ticket = 5; public void run(){ while(true){ System.out.println("Runnable ticket = " + ticket--); if(ticket < 0){ break; } } } }通过 线程名.setPriority()的方法设置,线程优先级的范围是:1-10,默认为5
package cn.itcast_04; /* * 我们的线程没有设置优先级,肯定有默认优先级。 * 那么,默认优先级是多少呢? * 如何获取线程对象的优先级? * public final int getPriority():返回线程对象的优先级 * 如何设置线程对象的优先级呢? * public final void setPriority(int newPriority):更改线程的优先级。 * * 注意: * 线程默认优先级是5。 * 线程优先级的范围是:1-10。 * 线程优先级高仅仅表示线程获取的 CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果。 * * IllegalArgumentException:非法参数异常。 * 抛出的异常表明向方法传递了一个不合法或不正确的参数。 * */ public class ThreadPriority extends Thread { @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(getName() + ":" + x); } } public class ThreadPriorityDemo { public static void main(String[] args) { ThreadPriority tp1 = new ThreadPriority(); ThreadPriority tp2 = new ThreadPriority(); ThreadPriority tp3 = new ThreadPriority(); tp1.setName("东方不败"); tp2.setName("岳不群"); tp3.setName("林平之"); // 获取默认优先级 //System.out.println(tp1.getPriority()); //5 //System.out.println(tp2.getPriority()); //5 //System.out.println(tp3.getPriority()); //5 // 设置线程优先级 // tp1.setPriority(100000);//IllegalArgumentException:非法参数异常。 // 设置正确的线程优先级 tp1.setPriority(10); tp2.setPriority(1); tp1.start(); tp2.start(); tp3.start(); } }线程安全出现的根本原因:
存在两个或者两个以上的线程对象共享同一个资源;多线程操作共享资源代码有多个语句。解决方法:通过同步操作来解决。 同步操作:一个代码块中的多个操作在同一时间段内只能由一个线程进行,其他线程要等待此线程完成后才可以继续执行。 三种方法实现同步操作:
同步代码块: synchronized(this){ //需要被同步操作的代码 } 应用实例: 实现卖票程序 public class RunnableImpl implements Runnable{ //定义一个多线程共享的票源 private int ticket = 100; //设置线程任务:卖票 @Override public void run() { while(true){ //先判断票是否存在 synchronized (this){ if (ticket>0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } //票存在,卖票 System.out.println(Thread.currentThread().getName() + "->>正在卖第" + ticket + "张票"); ticket--; }else { break; } } } } } 同步函数: 利用synchronized定义的函数。 同步函数就是使用synchronized修饰一个函数 //实现卖票程序 public class RunnableImpl implements Runnable{ //定义一个多线程共享的票源 private int ticket = 100; //设置线程任务:卖票 @Override public void run() { while(true){ sale(); } } public synchronized void sale(){ //先判断票是否存在 synchronized (this){ if (ticket>0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } //票存在,卖票 System.out.println(Thread.currentThread().getName() + "->>正在卖第" + ticket + "张票"); ticket--; } } } } Lock锁: 三步走。1.创建ReentrantLock对象 2.获取锁 3.释放锁 //实现卖票程序 public class RunnableImpl implements Runnable{ //定义一个多线程共享的票源 private int ticket = 100; //1.创建ReentrantLock对象 Lock lk = new ReentrantLock(); //设置线程任务:卖票 @Override public void run() { while(true){ //2.在可能出现线程安全的代码前调用Lock接口中的Lock方法获取锁. lk.lock(); if (ticket>0) { try { Thread.sleep(10); //票存在,卖票 System.out.println(Thread.currentThread().getName() + "->>正在卖第" + ticket + "张票"); ticket--; } catch (InterruptedException e) { e.printStackTrace(); }finally { //3.在可能出现线程安全的代码后释放锁。 lk.unlock(); } } } } }