线程就是程序执行的一条路径
创建线程两种方式对比:
- 继承Thread:可以直接使用Thread类中的方法,代码简单。但如果已经有了父类就不能使用这个方法(优先考虑)
- 实现Runnable接口:有了父类也没有关系,父类也可以实现接口,而且接口可以多实现。但需要先获得Thread对象后,才能获得Thread方法,代码复杂
两种方式源码对比:
- 继承Thread:由于子类重写了Thread类的run()方法,当调用start()方法,直接找子类的run()方法
- 实现Runnable接口:构造方法传入了Runnable的引用,成员变量记住了它,start()调用run()方法时内部判断成员变量Runnable的引用是否为空,不为空编译时看的是Runnable的run(),运行时执行的是子类的run()方法。
package day23;
public class Dk1EstablishThread {
//匿名内部类创建线程
public static void main(String[] args) {
//1.继承Thread
new Thread() {
public void run() { //重写run()方法
for (int i = 0; i < 10; i++) {
System.out.println("继承Thread");
}
}
}.start();;
//2.实现Runnable接口
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("实现Runnable接口");
}
}
}).start();
//两个线程交替执行
}
}
同步代码块:synchronized(锁){},任意对象都可以当作锁,匿名对象不行。
同步方法:
线程安全:Vector、StringBuffer、HashTable
线程不安全:ArrayList、StringBuilder、HashMap
Runtime类:
package day25;
public class Dk2Runtime {
//Runtime单例设计模式
public static void main(String[] args) {
Runtime r = Runtime.getRuntime();
//r.exec(dos命令);
}
}
Timer类:
sleep()和wait()方法区别:
-
sleep()方法必须传入参数,参数就是时间,当时间到了自动唤醒
wait()方法不是必须传入参数,如果没有参数遇到wait()就等待,如果传入参数,等参数的时间到了后等待
-
sleep()方法在同步中不释放锁,因为它可以自己醒来
wait()方法在同步中释放锁,因为它需要别人叫醒
package day25;
public class Dk3Wait {
//三个线程之间互相通信jdk1.5版本之前
public static void main(String[] args) {
// TODO Auto-generated method stub
Printer p = new Printer();
new Thread() {
public void run() {
while (true) {
try {
p.print1();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
while (true) {
try {
p.print2();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
while (true) {
try {
p.print3();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
}
}
class Printer {
private int flag = 1; //定义标记
private Object obj = new Object();
public void print1() throws InterruptedException {
synchronized (this) {
while (flag != 1) {
this.wait();
}
System.out.print("J");
System.out.print("a");
System.out.print("v");
System.out.print("a");
System.out.println();
flag = 2;
//this.notify(); //随机唤醒另一条线程
this.notifyAll(); //唤醒所有线程
}
}
public void print2() throws InterruptedException {
synchronized (this) {
while (flag != 2) {
this.wait();
}
System.out.print("P");
System.out.print("y");
System.out.print("t");
System.out.print("h");
System.out.print("o");
System.out.print("n");
System.out.println();
flag = 3;
this.notifyAll();
}
}
public void print3() throws InterruptedException {
synchronized (this) {
while (flag != 3) {
this.wait();
}
System.out.print("C");
System.out.print("+");
System.out.print("+");
System.out.println();
flag = 1;
this.notifyAll();
}
}
}
package day25;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Dk4Lock {
//互斥锁
public static void main(String[] args) {
Printer2 p = new Printer2();
new Thread() {
public void run() {
while (true) {
try {
p.print1();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
while (true) {
try {
p.print2();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
while (true) {
try {
p.print3();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
}
}
class Printer2 {
private ReentrantLock r = new ReentrantLock();
private Condition c1 = r.newCondition();
private Condition c2 = r.newCondition();
private Condition c3 = r.newCondition();
private int flag = 1; //定义标记
private Object obj = new Object();
public void print1() throws InterruptedException {
r.lock();
if (flag != 1) {
c1.await(); //也可以调用wait()
}
System.out.print("J");
System.out.print("a");
System.out.print("v");
System.out.print("a");
System.out.println();
flag = 2;
c2.signal();
r.unlock();
}
public void print2() throws InterruptedException {
r.lock();
if (flag != 2) {
c2.await();
}
System.out.print("P");
System.out.print("y");
System.out.print("t");
System.out.print("h");
System.out.print("o");
System.out.print("n");
System.out.println();
flag = 3;
c3.signal();
r.unlock();
}
public void print3() throws InterruptedException {
r.lock();
if (flag != 3) {
c3.await();
}
System.out.print("C");
System.out.print("+");
System.out.print("+");
System.out.println();
flag = 1;
c1.signal();
r.unlock();
}
}
线程组:如果没有给定线程属于哪个组,默认就属于主线程组
package day25;
public class MyRunner implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "..." + i);
}
}
}
package day25;
public class Dk5ThreadGroup {
//线程组
public static void main(String[] args) {
MyRunner mr = new MyRunner();
ThreadGroup tg = new ThreadGroup("我是一个线程组");
Thread t1 = new Thread(tg,mr,"张三"); //将线程“张三”加入指定组
Thread t2 = new Thread(tg,mr,"李四");
System.out.println(tg.getName());
}
}
//输出
我是一个线程组
线程池:程序启动一个新线程成本较高,使用线程池可以提高性能,尤其程序中创建大量生存期很短的线程时。线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
从jdk1.5开始内置线程池
package day25;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Dk6ThreadPool {
//线程池
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2); //创建线程池,可以放两条线程
MyRunner mr1 = new MyRunner(); //创建Runnable的子类对象
MyRunner mr2 = new MyRunner();
pool.submit(mr1);
pool.submit(mr2);
pool.shutdown(); //关闭线程池,不接受新任务
}
}