Java中的线程
一个程序的运行须要启动一个应用进程,一个进程能够创建多个线程。帮助应用完毕多任务操作。实现并发运行。在Java中线程是被封装成Thread
类。进行多线程操作时仅仅须要继承一个Thread
类,实现自己的功能就可以。然后开启此线程,或者你也能够实现一个Runnable
接口。然后将其传递给Thread
对象。然后再启动它。
线程的创建于启动
继承Thread
创建一个类并继承Thread
类,然后实现Thread
类的run
方法,在run
方法内填上自己的代码。然后创建这个自己定义类,并调用其start
方法来启动这个自己定义线程。
// 引入Thread
import java.lang.Thread;
/**
* 创建自己的Thread,实现run方法(放上自己要运行的内容)
*/
class MyThread extends Thread {
/**
* 覆盖超类Thread的run方法
*/
public void run() {
for(int i=0; i<10; i++) {
System.out.println("第" + i + "次循环");
}
}
}
class ThreadDemo1 {
public static void main(String[] args) {
// 创建一个自己定义线程。而且启动它
new MyThread().start();
}
}
/* 程序输出:
第0次循环
第1次循环
第2次循环
第3次循环
第4次循环
第5次循环
第6次循环
第7次循环
第8次循环
第9次循环
*/
实现Runnable
一个实现过Runnable
的对象都能够被一个Thread
对象所运行。
import java.lang.Thread;
import java.lang.Runnable;
/**
* 创建一个类,实现Runnable接口。
*/
class MyRunnable implements Runnable {
/**
* 实现Runnable的run方法
*/
public void run() {
for(int i=0; i<5; i++) {
System.out.println("Runable:第" + i + "次循环");
}
}
}
class ThreadDemo2 {
public static void main(String[] args) {
// 创建一个线程。并创建一个实现过Runnable的对象
// 构造它,然后再启动这个线程
new Thread(new MyRunnable()).start();
}
}
/* 程序输出:
Runable:第0次循环
Runable:第1次循环
Runable:第2次循环
Runable:第3次循环
Runable:第4次循环
*/
synchronized
的使用
既然是多线程。那么就会出现多线程的问题。如同一时候訪问同一资源。从而产生意料之外的结果。这是我们所不想看到的。在Java中能够非常easy的解决问题。使用synchronized
对操作进行加锁。synchronized
能够对对象加锁,也能够对函数进行加锁。以下对照一下未使用synchronized
和使用synchronized
的不同之处。
未使用synchronized
的情况
import java.lang.Thread;
import java.lang.Runnable;
class MyRunnable implements Runnable {
private static int i=0;
public void run() {
for(; i<10; i++) {
try {
Thread.sleep(10);
} catch(Exception e) {
}
print(i);
}
}
private void print(int k) {
System.out.println(k);
}
}
class Demo {
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
new Thread(r).start();
new Thread(r).start();
}
}
能够看到结果不对,由于两个线程可能会同一时候进入线程,然后打印出两个同样的值。
0
0
2
3
4
5
6
7
8
9
10
使用了synchronized
后的情况
import java.lang.Thread;
import java.lang.Runnable;
class MyRunnable implements Runnable {
private static int i=0;
public void run() {
synchronized(this) {
for(; i<10; i++) {
try {
Thread.sleep(10);
} catch(Exception e) {
}
print(i);
}
}
}
private void print(int k) {
System.out.println(k);
}
}
class Demo {
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
new Thread(r).start();
new Thread(r).start();
}
}
当对for
进行加锁处理后,便不会同一时候两个线程进入循环,这样打印的数字便不会出错。
0
1
2
3
4
5
6
7
8
9
synchronized
的加锁对象会有一个标志位(0/1)。默认的情况下是0,当线程运行到synchronized
的加锁对象后假设对象的标志位为0。那么将其设置为1,否则等待。
这个标志位能够称之为“锁旗标”。这样以来便能够实现线程同步。
尽管synchronized
攻克了多线程的不安全问题。可是也是有一定的弊端的。它会减少程序的运行效率,所以。synchronized
不能够任意放置,应尽量将其放到必须使用的位置上。
如单例模式的一个样例:
public class Single {
private Single mInstance;
private Single(){
}
public static Single getInstance() {
if(mInstance == null) {
synchronized(Single.class) {
if(mInstance == null) {
mInstance = new Single();
}
}
}
return mInstance;
}
}
这里的synchronized
能够加在getInstance()
前面,可是这样会大大减少运行效率,也能够去掉外层的if(mInstance == null)
,可是这样也会添加不必要的推断,以为假设mInstance
已经创建后便不须要锁了。若此以来,上面这样的写法是最好的。
最内层的if
推断有必要说明一下,能够假设这样一种情况,两个线程都运行到第一个if
的后面,那么。假设没有内层的if
推断的话,mInstance
会被创建两次,所以,内层的if
是不可或缺的。
wait
和notify
的使用
wait
和notify
是Object对象中的两个方法。其作用是用于多线程中的控制,如想使用两个线程交替打印出Odd
和Even
时,详细代码例如以下:
import java.lang.Thread;
import java.lang.Runnable;
class Temp {
public static boolean flag = false;
}
class Odd implements Runnable{
public void run() {
while(true) {
if(Temp.flag) {
try {
wait();
} catch(Exception e) {}
}
System.out.println("Odd");
Temp.flag = !Temp.flag;
try {
notify();
} catch(Exception e) {}
}
}
}
class Even implements Runnable {
public void run() {
while(true) {
if(!Temp.flag) {
try {
wait();
} catch(Exception e) {}
}
System.out.println("Even");
Temp.flag = !Temp.flag;
try {
notify();
} catch(Exception e) {}
}
}
}
class Demo {
public static void main(String[] args) {
new Thread(new Odd()).start();
new Thread(new Even()).start();
}
}
当然除了notify
方法,还有notifyAll
方法。用于唤醒全部线程。
Lock的使用
JDK1.5之后。也就是Java5.0之后。添加了很多新的内容,如用于线程控制的一些类,Lock
的用法相当于synchronized
,Lock
中lock()
和unlock()
分别用于加锁和解锁,一般用法例如以下:
import java.lang.Runnable;
import java.lang.Thread;
import java.util.concurrent.locks.*;
class Locks implements Runnable {
private Lock lock = new ReentrantLock();
private int index = 0;
public void run() {
while(true) {
lock.lock();
System.out.print(index + " ");
try {
Thread.sleep(100);
} catch(Exception e) {}
index ++;
lock.unlock();
}
}
}
class Demo {
public static void main(String[] args) {
Locks locks = new Locks();
new Thread(locks).start();
new Thread(locks).start();
new Thread(locks).start();
}
}
这样便能够顺序打印出0 1 2 3 4 ···
。
通过Lock
的对象,我们能够创建Condition对象,如
Condition condition = lock.newCondition();
然后能够使用condition.await();
和condition.signal()
来暂停和唤醒线程,当然还有condition.signalAll()
来唤醒全部线程。