线程和多线程总结

  首先说一下进程和线程的区别:

          进程:指正在运行的程序,当打开一个程序的时候,他会进入内存运行。它最大的特点是它需要内存。         

          什么是线程:线程是进程中的一个执行单元。

          什么是多线程: 一个程序有多个执行路径。

我们在学习一门技术的时候首先要知道这么技术有什么作用,能干什么用,那么我们学习线程有什么用?学习多线程有什么用?我们就抱着这样的问题来讨论以下线程和多线程。

      在我们未学线程的时候,我们都知道我们的程序是从main函数开始往下一条一条的按照顺序执行下去,但是现在我们有了线程之后就不再是那样了,我们现在程序可以开辟一条另外的执行路劲,让程序不再是“一条路走到黑”,下面来举个例:

public class TestThread {
	public static void main(String[] args) {
		NewThread nt = new NewThread();
		Thread t = new Thread(nt);
		t.start();
		int i;
		for(i = 0; i < 10; i++ ) {
			System.out.println("main..."+i);
		}
	}
}
public class NewThread implements Runnable {

	@Override
	public void run() {
		for(int j = 0; j < 10; j++) {
			System.out.println("new Thread..."+j);
		}	
	}
	
}

运行结果:

main...0
main...1
main...2
new Thread...0
new Thread...1
new Thread...2
new Thread...3
new Thread...4
new Thread...5
new Thread...6
new Thread...7
new Thread...8
new Thread...9
main...3
main...4
main...5
main...6
main...7
main...8
main...9

注意:每次运行的结果都不一样。因为这是根据CPU给他们分配的时间来决定的,每次都是不一样的。

在前面这个例子中我们可以看到如何去创建一个新的线程,新建一个类,去实现Runnable接口(也可以继承Thread类),然后重写里面的run方法。然后在主线程里面新建Thread类,把实现了Runnable接口的类作为构造器参数传给Thread,然后调用start方法就启动了一个新的线程。

每一个线程都是新开一个栈,这样才能达到多个线程的无序执行。

线程的几种状态:

new状态:新建状态

Runanble状态:运行状态

Blocking状态:阻塞,具有CUP执行资格,也就是说,CPU一有空闲那么就会退出阻塞状态进入运行状态

Waiting:等待状态,唤醒之后有可能进入阻塞状态或者是运行状态

Timed_waiting:休眠状态,也就是调用sleep,在指定的时间内可以醒来。

Terminated:死亡状态

 

多线程:

什么是多线程:

        其实在我们程序中,每次去创建一个线程,调用执行这一系列的操作都需要消耗大量的时间,那么对我们程序的整个性能也会带来很大的损耗,所以我们就出现了多线程技术,多线程技术的原理其实很简单,比如说我们有一个鱼缸,然后把我们的每个线程当成鱼一样拿到鱼缸里面养着,当我们需要的时候就取出来用,当我们用完之后就又放回去,鱼缸其实它就是一个容器。

在我们java中这样的鱼缸已经帮我们制定好了,我们只需要拿来用就可以了。

    在java.util.concurrent.Executors;下面有这样一个方法

static ExecutorServicenewFixedThreadPool(int nThreads)
          创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程

 可以看到它是static的,返回值是ExecutorService,在它里面有一个submit方法,把我们写好的线程(实现Runnable接口或者Callable接口的类)作为参数传给他,那么他就会启动。

Collable接口:

    在我们使用线程池技术的时候,我们一般会用submit来提交一个线程任务,但是submit需要一个实现了Runnable(也可以是Callable)接口的实现类作为参数,但是我们都知道,实现Runnable接口的run方法没有返回值,没有抛出异常,这就为我们带来了很大的不便。

    但是我们前面提到的Callable接口,可以有返回值,也可以抛出异常,但是在使用方面确实带来了一点点麻烦,它在作为submit方法的参数时,那么submit会返回一个Future接口的实现类,然后调用里面的get方法即可拿到返回值。

代码:

public class ThreaPool {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ExecutorService es =  Executors.newFixedThreadPool(2);
		System.out.println(es);
		Future<String> f = es.submit(new ThreadPoolCallable());
		String s = f.get();
		System.out.println(s);
	}
public class ThreadPoolCallable implements Callable<String> {

	@Override
	public String call() throws Exception {
		// TODO Auto-generated method stub
		return "abc";
	}
	

synchronized关键字:

         这是关于使用线程带来的问题,就是代码同步的问题,前面说过,线程之间CPU分配的时间是随机的,那么就可能引来很大的问题,synchronized就是来解决这个问题的。

     

synchronized(obj){
	synchronized(obj){
		if( ticket > 0){
			try{
			   Thread.sleep(10);
			}catch(Exception ex){}
			System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);
		}
	}

  obj是一个对象锁,可以是任意类,那么里面的就是同步代码块,里面需要放的是共享数据,就是假如说你买票,可以通过多个渠道来买(每个通道都是一个线程),那么票是定好的假如只有100张票,那么多个渠道来买这一百张票,就不能有错误,那么同步的作用就是当有个线程进入了同步代码块,其它的线程就不能进入同步代码块,必须等上一个线程出来,释放了同步锁(代码里面的obj),然后其它的线程才能进入访问。

也可以使用Lock接口的里面的lock和unlock来代替synchronized。

死锁:

原理:

   前面说过,线程是根据cpu分配的时间来的,那么想一想会不会出现这样一种尴尬的局面,就是线程一进入了A抱着A锁,而线程B进入了B抱着B锁,那么现在线程一需要B锁,线程二需要A锁,这两各自抱着自己的锁谁也不放手,这就形成了死锁。

代码:

public class DeadRunnable implements Runnable {

	private int i = 0;
	public void run() {
		while(true) {
			if(i%2 == 0) {
				synchronized(Lock_A.lockA) {
					System.out.println("if...LockA");
					synchronized(Lock_B.lockB) {
						System.out.println("if...LockB");
					}
				}
			}else {
				synchronized(Lock_B.lockB) {
					System.out.println("else...LockB");
					synchronized(Lock_A.lockA) {
						System.out.println("else...LockA");
					}
				}
			}
			i++;
		}
	}
}
public class Lock_A {
	private Lock_A() {	
	}
	
	final static Lock_A lockA = new  Lock_A();
}
public class Lock_B {
	private Lock_B() {	
	}
	
	final static Lock_B lockB = new  Lock_B();
}
public class Main {
	public static void main(String[] args) {
		DeadRunnable dr = new DeadRunnable();
		Thread t1 = new Thread(dr);
		Thread t2 = new Thread(dr);
		t1.start();
		t2.start();
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值