1.实现方式:
多线程的实现方式有两种方式,一种是继承Thread类,一种是实现runnable接口。
继承thread类:
package com.heima.thread;
public class Demo2_Thread {
/**
* @param args
*/
public static void main(String[] args) {
MyThread mt = new MyThread(); //4,创建Thread类的子类对象
mt.start(); //5,开启线程
for(int i = 0; i < 1000; i++) {
System.out.println("bb");
}
}
}
class MyThread extends Thread { //1,继承Thread
public void run() { //2,重写run方法
for(int i = 0; i < 1000; i++) { //3,将要执行的代码写在run方法中
System.out.println("aaaaaaaaaaaa");
}
}
}
接口方式:
package com.heima.thread;
public class Demo3_Thread {
/**
* @param args
*/
public static void main(String[] args) {
MyRunnable mr = new MyRunnable(); //4,创建Runnable的子类对象
//Runnable target = mr; mr = 0x0011
Thread t = new Thread(mr); //5,将其当作参数传递给Thread的构造函数
t.start(); //6,开启线程
for(int i = 0; i < 1000; i++) {
System.out.println("bb");
}
}
}
class MyRunnable implements Runnable { //1,定义一个类实现Runnable
@Override
public void run() { //2,重写run方法
for(int i = 0; i < 1000; i++) { //3,将要执行的代码写在run方法中
System.out.println("aaaaaaaaaaaa");
}
}
}
2.休眠线程(sleep)
Thread.sleep(毫秒,纳秒), 控制当前线程休眠若干毫秒1秒= 1000毫秒 1秒 = 1000 * 1000 * 1000纳秒 1000000000
new Thread() {
public void run() {
for(int i = 0; i < 10; i++) {
System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
3.守护线程(setDaemon())
设置一个线程为守护线程, 该线程不会单独执行, 当其他非守护线程都执行结束后, 自动退出
Thread t1 = new Thread() {
public void run() {
for(int i = 0; i < 50; i++) {
System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t2 = new Thread() {
public void run() {
for(int i = 0; i < 5; i++) {
System.out.println(getName() + "...bb");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.setDaemon(true); //将t1设置为守护线程
t1.start();
t2.start();
4.加入线程(* join())
当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续
- join(int), 可以等待指定的毫秒之后继续
final Thread t1 = new Thread() {
public void run() {
for(int i = 0; i < 50; i++) {
System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t2 = new Thread() {
public void run() {
for(int i = 0; i < 50; i++) {
if(i == 2) {
try {
//t1.join(); //插队,加入
t1.join(30); //加入,有固定的时间,过了固定时间,继续交替执行
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(getName() + "...bb");
}
}
};
t1.start();
t2.start();
5.礼让线程
- yield让出cpu
6.设置线程的优先级
- setPriority()设置线程的优先级
7.同步代码块
- 1.什么情况下需要同步
- 当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步.
- 如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码.
- 2.同步代码块
- 使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块
- 多个同步代码块如果使用相同的锁对象, 那么他们就是同步的
class Printer {
Demo d = new Demo();
public static void print1() {
synchronized(d){ //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
System.out.print("程");
System.out.print("序");
System.out.print("员");
System.out.print("\r\n");
}
}
public static void print2() {
synchronized(d){
System.out.print("1");
System.out.print("2");
System.out.print("3");
System.out.print("4");
System.out.print("\r\n");
}
}
}
8.同步方法
- 使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的
class Printer {
public static void print1() {
synchronized(Printer.class){ //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
System.out.print("程");
System.out.print("序");
System.out.print("员");
System.out.print("\r\n");
}
}
/*
* 非静态同步函数的锁是:this
* 静态的同步函数的锁是:字节码对象
*/
public static synchronized void print2() {
System.out.print("1");
System.out.print("2");
System.out.print("3");
System.out.print("4");
System.out.print("\r\n");
}
}
9.线程安全问题
- 多线程并发操作同一数据时, 就有可能出现线程安全问题
- 使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作
public class Demo2_Synchronized {
/**
* @param args
* 需求:铁路售票,一共100张,通过四个窗口卖完.
*/
public static void main(String[] args) {
TicketsSeller t1 = new TicketsSeller();
TicketsSeller t2 = new TicketsSeller();
TicketsSeller t3 = new TicketsSeller();
TicketsSeller t4 = new TicketsSeller();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t4.setName("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class TicketsSeller extends Thread {
private static int tickets = 100;
static Object obj = new Object();
public TicketsSeller() {
super();
}
public TicketsSeller(String name) {
super(name);
}
public void run() {
while(true) {
synchronized(obj) {
if(tickets <= 0)
break;
try {
Thread.sleep(10);//线程1睡,线程2睡,线程3睡,线程4睡
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "...这是第" + tickets-- + "号票");
}
}
}
}
10.两个线程间的通信
- 1.什么时候需要通信
- 多个线程并发执行时, 在默认情况下CPU是随机切换线程的
- 如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次打印
- 2.怎么通信
- 如果希望线程等待, 就调用wait()
- 如果希望唤醒等待的线程, 就调用notify();
- 这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用
public class TestTwoThread {
public static void main(String[] args) {
printer p = new printer();
new Thread() {
public void run() {
while(true) {
try {
p.print1();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
while(true) {
try {
p.print2();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
}
}
class printer {
int flag = 1;
public void print1() throws InterruptedException {
synchronized (this) {
while(flag!=1) {
this.wait();
}
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.println();
flag=2;
this.notify(); //随机唤醒当前wait状态的线程
}
}
public void print2() throws InterruptedException {
synchronized (this) {
while(flag!=2) {
this.wait();
}
System.out.print("1");
System.out.print("2");
System.out.print("3");
System.out.println();
flag=1;
this.notify();
}
}
}
11.用ReentrantLock和Codintion方式去实现两个进程的通讯
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TestTwoThread2 {
public static void main(String[] args) {
printer2 p = new printer2();
new Thread() {
public void run() {
while(true) {
try {
p.print1();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
while(true) {
try {
p.print2();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
}
}
class printer2 {
int flag = 1;
private ReentrantLock r = new ReentrantLock();
private Condition c1 = r.newCondition();
private Condition c2 = r.newCondition();
public void print1() throws InterruptedException {
r.lock();
if(flag!=1) {
c1.await();
}
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.println();
flag=2;
c2.signal();
r.unlock();
}
public void print2() throws InterruptedException {
r.lock();
if(flag!=2) {
c2.await();
}
System.out.print("1");
System.out.print("2");
System.out.print("3");
System.out.println();
flag=1;
c1.signal();
r.unlock();
}
}