实现线程的方法有继承Thread和实现Runable接口。大多数的话会使用Runable接口,实现接口的好处:1就是避免Java单继承的局限性 2.把线程代码和任务代码分离,解耦合,拓展性好。下面简单的介绍一下线程类的使用,这里只使用实现接口的方式。
package cn.test; public class Mytask implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread()+"====="+i); } } public static void main(String[] args) { // 创建任务类对象 Mytask mytask = new Mytask(); // 创建线程任务类 Thread t1 = new Thread(mytask,"线程1"); Thread t2 = new Thread(mytask, "线程2"); // 启动线程 t1.start(); t2.start(); // 主函数中的代码 for(int i=0;i<10;i++) { System.out.println("主函数: "+i); } } }
对于上述的案列中,线程类实现run方法,每次执行,使线程睡眠一段时间。主函数类中,创建任务类对象,线程对象,开启线程,主函数代码。所有的执行顺序都是随机的,不确定性。下面再看看使用匿名内部类的用法使用线程,代码如下:
package cn.test; public class SecondTask{ public static void main(String[] args) { Runnable runnable = new Runnable() { @Override public void run() { for(int i=0;i<100;i++) { System.out.println(Thread.currentThread().getName()+"====="+i); } } }; // 创建类对象 SecondTask task = new SecondTask(); // 线程对象 Thread t1=new Thread(runnable,"线程1"); Thread t2=new Thread(runnable,"线程2"); // 启动线程 t1.start(); t2.start(); } }
使用匿名内部类的好处就是方便实现每个线程执行不同的线程任务操作。下面的一串代码是一个经典的线程卖票问题,使用到同步,代码块。最关键的是票的总数是100,假如A买了一张票,B买了一张票,这是票的总数是98,而不是99等这样的问题。话不多数,先上代码:
线程任务类:
package cn.test; public class TicketTask implements Runnable{ // 定义票的总数 private int tick=100; // 定义同步对象锁 private Object obj=new Object(); @Override public void run() { while(true) { synchronized (obj) { //进来上锁,其他线程无法进来 if(tick>0) { // 业务操作 System.out.println(Thread.currentThread().getName()+"===="+tick); // 剩余票数 tick--; } } } } }
主方法调用:
package cn.test; public class SellTicket { public static void main(String[] args) { // 创建线程任务对象 TicketTask t1 = new TicketTask(); // 创建线程对象 Thread xc1 = new Thread(t1, "线程1"); Thread xc2 = new Thread(t1, "线程2"); Thread xc3 = new Thread(t1, "线程3"); Thread xc4 = new Thread(t1, "线程4"); // 启动线程 xc1.start(); xc2.start(); xc3.start(); xc4.start(); } }