JAVA线程的详细说明

多线程的定义:
多线程是一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立。线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。

在JAVA中实现多线程:
java作为一个完全面向对象的语言,提供了 java.lang.Thread 类来方便多线程编程,这个类提供了大量的方法来方便我们控制自己的各个线程。

在JAVA中建立线程有2个方法——继承 Thread 类和实现 Runnable 接口。
1、继承Thread类
重写方法 run(),我们在创建的 Thread 类的子类中重写 run() ,加入线程所要执行的代码即可。
例子如下:

public class Thread1 extends Thread {
    public void run() {
        for ( int i = 0; i < 10; i++ ) {
            System.out.println("New thread——"+i);
        }
    }
    public static void main(String[] args) {
        Thread1 t1 = new Thread1();
        t1.start();
        for ( int i = 0; i < 10; i++ ) {
            System.out.println("Main thread");
        }
    }
}

2、实现 Runnable 接口
Runnable 接口只有一个方法 run(),我们声明自己的类实现 Runnable 接口并提供这一方法,然后重写该方法。但是 Runnable 接口并没有任何对线程的支持,我们还必须创建 Thread 类的实例,这一点通过 Thread 类的构造函数public Thread(Runnable ***);来实现。
例子如下:

public class Thread2 implements Runnable {
	int count=1, number;
	public Thread2(int number) {
		this.number = number;
		System.out.println("创建线程 " + number);
	}
	public void run() {
		while(true) {
			System.out.println("线程 " + number + ":计数 " + count);
			if(++count== 6) return;
		}
	}
public static void main(String args[]) {		
		Thread2 t=new Thread2(3);
		Thread t2=new Thread(t);
		t2.start();//另一种简单写法:new Thread(new Thread2(3)).start();
	}
}

线程的同步:
由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。
我们只需针对方法提出一套机制,这套机制就是 synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。
synchronized的详细说明我会在另一篇中详细介绍。

线程的阻塞:
为了解决对共享存储区的访问冲突,Java 引入了同步机制,现在让我们来考察多个线程对共享资源的访问,但是在任意时刻所要求的资源不一定已经准备好了被访问,反过来,同一时刻准备好了的资源也可能不止一个。所以为了解决这种情况下的访问控制问题,Java 引入了阻塞机制。
阻塞指的是暂停一个线程的执行以等待某个线程发生(如某资源就绪)。Java 提供了大量方法来支持阻塞,下面让对它们逐一分析。
1、 yield()方法
yield()使得线程放弃当前分得的 CPU 时间,但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。调用 yield()的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程,但这个线程会在未来的一个时间点继续执行。
2、 sleep()方法
sleep(int time)使得线程在指定的时间内进入阻塞状态,time表示指定的时间,调用这个方法后不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态。
3、suspend()和resume()方法
两个方法是配套使用的,在我的理解中这两个方法就像一个开关,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume()被调用,才能使得线程重新进入可执行状态。在我的理解中这两个方法就像一个开关,suspend()表示开关断开,电流不能通过,resume()表示开关闭合,电流能通过。
4、wait()和 notify()方法
这两个方法也是配套使用的,wait()使得线程进入阻塞状态,它有两种形式(wait(int time) 、wait()),一种允许指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的 notify()被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify()被调用。形式上和第三种方法类似。
5、join()方法
Thread的join()方法可用于让当前线程阻塞,以等待特定线程的消亡。

3和4区别:
核心在于1,2,3的方法阻塞时都不会释放占用的锁,而4方法会释放占用的锁。

由此我们可以深究一下它们之间的区别:
首先,1,2,3方法都隶属于Thread 类,但是4方法却直接隶属于 Object 类,也就是说,所有对象都拥有这一对方法。因为这一对方法阻塞时要释放占用的锁,而锁是任何对象都具有的,调用任意对象的 wait()方法导致线程阻塞,并且该对象上的锁被释放。而调用任意对象的notify()方法则导致因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。
其次,1,2,3方法都可在任何位置调用,但是4方法却必须在 synchronized 方法或块中调用,毕竟只有在synchronized 方法或块中当前线程才占有锁,才有锁可以释放。
wait()和 notify()方法的上述特性决定了它们经常和synchronized 方法或块一起使用,将它们和操作系统的进程间通信机制作一个比较就会发现它们的相似性:synchronized方法或块提供了类似于操作系统原语的功能,它们的结合用于解决各种复杂的线程间通信问题。
关于 wait()和 notify()方法最后再说明两点:
第一:调用 notify()方法导致解除阻塞的线程是从因调用该对象的 wait()方法而阻塞的线程中随机选取的,我们无法预料哪一个线程将会被选择,所以编程时要特别小心,避免因这种不确定性而产生问题。
第二:除了 notify(),还有一个方法 notifyAll()也可起到类似作用,唯一的区别在于,调用 notifyAll()方法将把因调用该对象的wait()方法而阻塞的所有线程一次性全部解除阻塞。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值