------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一.创建线程
1.继承Thread
定义类继承Thread类
重写Thread类的run()方法
创建该类对象
调用start()方法即可开启新线程, 新线程会自动执行run()方法
class ThreadDemo1 {
public static void main(String[] args) {
System.out.println("程序开始");
// 创建线程对象, 调用start()方法, 程序会开启一条新线程, 新线程上执行run()方法
MyThread mt = new MyThread();
mt.start(); // 开新线程找run()方法, 自己重写了, 就找自己的
for (int i = 1; i <= 100; i++)
System.out.println("A " + i);
System.out.println("程序结束");
}
}
// 定义类继承Thread类
class MyThread extends Thread {
// 重写run方法
public void run() {
// 将新线程中要做的事放在run方法中
for (int i = 1; i <= 100; i++)
System.out.println("B " + i);
}
}
2.实现Runnable
定义类实现Runnable接口
实现Runnable接口的run()方法
创建自定义Runnable对象
创建Thread对象, 将Runnable对象传入Thread类的构造函数
调用start()方法即可开启新线程, 新线程会自动执行Runnable的run()方法
class ThreadDemo2 {
public static void main(String[] args) {
System.out.println("主线程开始");
// 创建自定义的Runnable, 创建Thread对象将Runnable传入, 调用Thread的start(). 开启新线程, 新线程就会执行Runnable的run()方法
MyRunnable mr = new MyRunnable();
Thread t = new Thread(mr);
t.start(); // 开新线程找run()方法, Thread类的run()方法判断有没有传Runnable, 传了就执行Runnable的run()
for (int i = 1; i <= 100; i++)
System.out.println("A " + i);
System.out.println("主线程结束");
}
}
// 定义类实现Runnable接口
class MyRunnable implements Runnable {
// 重写run()方法
public void run() {
// 将新线程要做的事写在run()方法中
for (int i = 1; i <= 100; i++)
System.out.println("B " + i);
}
}
3.使用匿名内部类
newThread(){
publicvoid run(){
}}.start();
newThread(new Runnable(){
publicvoid run(){
}}).start();
class ThreadDemo3 {
public static void main(String[] args) {
//
// 定义Thread类的子类, 创建对象, 调用start()方法
new Thread(){
public void run() {
for (int i = 1; i <= 100; i++)
System.out.println(getName() + ": A " + i);
}
}.start();
// 定义Runnable子类, 创建对象, 将Runnable对象传入Thread类的构造函数, 调用start()方法
new Thread(new Runnable(){
public void run() {
for (int i = 1; i <= 100; i++)
System.out.println(Thread.currentThread().getName() + ": B " + i);
}
}).start();
}
}
二.线程常用方法
1.currentThread
静态方法, 获取当前的线程对象
2.getName,setName
获取和设置线程的名字
class ThreadMethodDemo1 {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr, "线程1");
Thread t2 = new Thread(mr, "线程2");
t1.start();
t2.start();
}
}
class MyRunnable implements Runnable {
public void run() {
for (int i = 1; i <= 1000; i++)
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
3.sleep
静态方法, 控制当前线程休眠指定毫秒
class ThreadMethodDemo2 {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr, "线程1");
Thread t2 = new Thread(mr, "线程2");
t1.start();
t2.start();
}
}
class MyRunnable implements Runnable {
public void run() {
for (int i = 1; i <= 1000; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
Thread.sleep(1000); // 线程休眠1000毫秒, 由于Runnable中的run()没有声明异常, 所以只能catch
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
4.setDaemon
设置指定线程为守护线程, 守护线程不会单独运行
class ThreadMethodDemo3 {
public static void main(String[] args) {
Thread t1 = new Thread(){
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("A " + i);
try {
Thread.sleep(1000);
} catch(Exception e) {
e.printStackTrace();
}
}
}
};
Thread t2 = new Thread(){
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println("B " + i);
try {
Thread.sleep(1000);
} catch(Exception e) {
e.printStackTrace();
}
}
}
};
t2.setDaemon(true); // 将t2线程设置为守护线程, 如果程序中只剩守护线程了, 程序直接结束
t1.start();
t2.start();
}
}
5.join
当前线程暂停, 等待指定线程执行完毕后再继续
class ThreadMethodDemo4 {
public static void main(String[] args) {
final Thread t1 = new Thread(){
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("A " + i);
try {
Thread.sleep(1000);
} catch(Exception e) {
e.printStackTrace();
}
}
}
};
Thread t2 = new Thread(){
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("B " + i);
try {
Thread.sleep(1000);
if (i == 2)
t1.join(); // 当前线程暂停, 等待t1线程执行结束之后再继续
} catch(Exception e) {
e.printStackTrace();
}
}
}
};
t1.start();
t2.start();
}
}
三.同步
1.什么是同步
在多线程并发访问同一资源时,有可能出现线程安全问题.
为了解决这种问题, 我们就可以使用同步技术.
将多个线程访问资源的代码进行同步.
2.同步代码块
将需要同步的代码放在synchronized(){} 代码块中, 在小括号中指定锁对象
多段使用相同锁的同步代码块,同一时间只能执行一个, 必须等待一个执行结束后其他的才能继续执行
3.同步方法
如果整个方法内的代码都需要同步, 可以在方法前加上synchronized修饰
只有在同一个类中的几个方法可以使用同步方法的形式进行同步, 如果不同类中的几个方法想要同步, 必须使用同步代码块
因为同步方法默认使用this作为锁对象
4.死锁
多线程并发执行时, 如果多段同步代码嵌套使用,有可能互相冲突产生死锁, 导致程序阻塞.
在编程的过程中尽量不要将同步代码嵌套使用, 避免产生死锁.
class DeadLockDemo {
private static Object obj1 = new Object();
private static Object obj2 = new Object();
public static void main(String[] args) {
new Thread(){
public void run() {
synchronized(obj1) {
System.out.println("第一条线程锁定obj1");
synchronized(obj2) { // 要等21行执行结束
System.out.println("第一条线程锁定obj2");
}
}
}
}.start();
new Thread(){
public void run() {
synchronized(obj2) {
System.out.println("第二条线程锁定obj2");
synchronized(obj1) { // 要等12行执行结束
System.out.println("第二条线程锁定obj1");
}
}
}
}.start();
}
}
四.通信
1.什么是通信
在多线程并发执行的时候, 可以使用wait()和notify()方法在多个线程间互相通信
2.怎么使用
通信的代码必须写在同步代码中, 必须使用锁对象来调用wait()和notify()
wait()方法可以控制当前线程等待,直到其他线程调用notify()或者notifyAll()方法才被唤醒
五.JDK5的同步
1.怎么同步
使用ReentrantLock类的lock()方法开始同步
使用ReentrantLock类的unlock()方法结束同步
2.注意
解锁的代码unlock()方法一定要执行, 尽量放在finally中
六.JDK5的通信
1.怎么通信
先用ReentrantLock调用newCondition()方法获得Condition对象
使用Condition对象的await()方法等待
使用Condition对象的signal()方法唤醒
2.JDK5和以前通信的区别
JDK5之前只能使用锁对象wait()和notify().
多个线程只能在同一个对象上等待, 唤醒的时候要么唤醒随机一个, 要么唤醒所有的, 无法指定唤醒其中一个.
JDK5之后可以创建多个Condition对象, 不同的线程使用不同的Condition
唤醒的时候可以唤醒指定的Condition
七.练习
开启3条线程, 轮流执行打印操作
import java.util.concurrent.locks.*;
/*
开启3条线程, 轮流执行打印操作, 执行结果如下:
线程1: 1
线程1: 2
线程1: 3
线程2: 4
线程2: 5
线程2: 6
线程3: 7
线程3: 8
线程3: 9
线程1: 10
线程1: 11
线程1: 12
线程2: 13
线程2: 14
线程2: 15
线程3: 16
线程3: 17
线程3: 18
线程1: 19
线程1: 20
线程1: 21
线程2: 22
线程2: 23
线程2: 24
线程3: 25
线程3: 26
线程3: 27
*/
class WorkDemo {
public static void main(String[] args) {
final Print p = new Print();
new Thread(){
public void run() {
for(int i = 0; i < 3; i++)
try {
p.print1();
} catch(Exception e) {
e.printStackTrace();
}
}
}.start();
new Thread(){
public void run() {
for(int i = 0; i < 3; i++)
try {
p.print2();
} catch(Exception e) {
e.printStackTrace();
}
}
}.start();
new Thread(){
public void run() {
for(int i = 0; i < 3; i++)
try {
p.print3();
} catch(Exception e) {
e.printStackTrace();
}
}
}.start();
}
}
class Print {
/*JDK1.5以前的同步和通信使用
private static int i = 1;
private int flag = 1;
public synchronized void print1() throws Exception {
while (flag != 1)
this.wait();
System.out.println("线程1: " + i++);
System.out.println("线程1: " + i++);
System.out.println("线程1: " + i++);
System.out.println();
flag = 2;
this.notifyAll();
}
public synchronized void print2() throws Exception {
while (flag != 2)
this.wait();
System.out.println("线程2: " + i++);
System.out.println("线程2: " + i++);
System.out.println("线程2: " + i++);
System.out.println();
flag = 3;
this.notifyAll();
}
public synchronized void print3() throws Exception {
while (flag != 3)
this.wait();
System.out.println("线程3: " + i++);
System.out.println("线程3: " + i++);
System.out.println("线程3: " + i++);
System.out.println();
flag = 1;
this.notifyAll();
}
*/
//jDK1.5以后的同步和通信使用
private static int i = 1;
private int flag = 1;
private ReentrantLock lock = new ReentrantLock(); //锁对象
private Condition c1 = lock.newCondition(); //使用lock对象获取一个和当前对象相关联的同步监视器
private Condition c2 = lock.newCondition(); //同步监视器
private Condition c3 = lock.newCondition(); //同步监视器
public void print1() throws Exception {
lock.lock(); //使用c1上锁
if (flag != 1)
c1.await(); //c1等待
System.out.println("线程1: " + i++);
System.out.println("线程1: " + i++);
System.out.println("线程1: " + i++);
System.out.println();
flag = 2;
c2.signal(); //唤醒c2
lock.unlock();
}
public void print2() throws Exception {
lock.lock(); //使用c2上锁
if (flag != 2)
c2.await(); //c2等待
System.out.println("线程2: " + i++);
System.out.println("线程2: " + i++);
System.out.println("线程2: " + i++);
System.out.println();
flag = 3;
c3.signal(); //唤醒c3
lock.unlock();
}
public void print3() throws Exception {
lock.lock(); //使用c3上锁
if (flag != 3)
c3.await(); //c3等待
System.out.println("线程3: " + i++);
System.out.println("线程3: " + i++);
System.out.println("线程3: " + i++);
System.out.println();
flag = 1;
c1.signal(); //唤醒c1
lock.unlock();
}
}
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------