Java线程

Java线程的三种写法

Thread

注意点:线程是根据CPU分配的时间片运行,有着不确定性。
线程的写法已:通过继承Thread类,并重写Thread中的run方法。

public class ThreadTest {
	public static void main(String[] args) {
		new Ta().start();
		new Ta().start();
	}
}
class Ta extends Thread {
	public void run() {
		for (int i = 100; i >0; i--) {
			System.out.println(Thread.currentThread().getName()+"\t"+i);
		}
	}
}

程序运行结果如下:

在这个程序中发现Thread 是非共享模式运行的,每个线程一旦创建就会各自执行Ta类中的run()方法(重写),也就是说每个线程都有属于自己的100个数,所以出现了上图中的重复打印。
需要注意的是,类要继承Thread,并重写run()方法,在程序的入口使用“.start()”,来启动线程。
这样写的弊端是Java只支持单继承,在代码的维护上就显得很麻烦
另外还可以通过新建对象来对线程命名,现将上面的代码修改如下如下:

Runnable

public class ThreadTest {
	public static void main(String[] args) {
		ThreadTest2 threadTest2 = new ThreadTest2();
		new Thread(threadTest2, "线程1").start();
		new Thread(threadTest2, "线程2").start();
	}
}
class ThreadTest2 implements Runnable {
	Integer x = 100;
	Object lock = new Object();
	public void run() {
		while (true) {
			synchronized (ThreadTest2.class) {
				try {
					Thread.sleep(500);
				} catch (Exception e) {}
				if (x > 0) {
					System.out.println(Thread.currentThread().getName() + "\t" + x--);
				} else break;
			}
		}
	} 
}

在这段代码中增加了对线程的命名,使用synchronized 关键字完成对资源共享的锁定,实现了Runnable接口,同时重写run()方法。
实现Runnable接口的方式同样是重写run()方法
实现效果如下:
在这里插入图片描述

Thread与Runnable

在两者的使用过程中,我们发现Thread与Runnable都对run()方法进行了重写,那么他们之间有什么关系吗?如下:
Thread类继承了根类,并实现了Runnable方法。

public class Thread extends Object implements Runnable

在实际的Thread类中的run()方法调了Runnable中run()方法,而Runnable中的run()方法是由其子类去完成具体的实现的,因而在选择使用继承Thread的方式后就得重写其中的run()方法。
观察此处往下的第二个代码块:当执行Thread中的run()方法时,若传入的target不为空时,就会执行target中的run()方法。即Thread实现了Runnale接口,并重写了含有run方法的子类中的run方法(这句话太拗口了)。

public interface Runnable { 
 	public abstract void run();}
public class Thread extends Object implements Runnable{
	Private Runnable target; 
	public Thread(Runnable target,String name){ 
   	 init(null,target,name,0); 
	} 
	@Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
 }

Java中规定了单继承,一旦选择继承Thread类就意味着不能将资源共享,具体可以参考第一个代码段。而Runnable则可以实现资源的有序共享。

代码规范

在使用Runnable时创建线程时我们用阿里代码规约扫描时,提示需要使用线程池而非线程,如图下图,线程池后面会写。
在这里插入图片描述

Callable

实现Callable接口,重写其的clall()方法。并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程。

public class ThreadTest {
	public static void main(String[] args) {
	Callable<Integer> myCallable = new MyCallable();  
	 FutureTask<Integer> futuretask = new FutureTask<Integer>(myCallable);
		Thread thread = new Thread(futuretask);
        thread.start(); 
	}
}
class MyCallable implements Callable<Integer> {
    private int i = 0;
    public Integer call() {
        int sum = 0;
        for (int i= 100; i > 0; i--) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            sum += i;
        }
        return sum;
    }
}

从代码中可以看出线程的实现由run()变成了call(),call()方法有返回值,注意数据类型为引用数据类型Integer,在线程使用数据类型应该是引用数据类型 。这种写法对我这种懒人来说不如前两种来的快,所以我比较喜欢前两种写法,在实际使用中较多使用线程池即

ExecutorService ServiceTable = Executors.newFixedThreadPool();

三种线程的创建使用

在实际使用中,由于java单继承特性的限定,我本人一般使用Runnable。在测试线程时,当目的达到应该进行中断处理,使用Thread.interrupt(),Thread.stop()停止已过时,但其实这些都是假的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值