多线程增加效率
- 并行, 就是多个任务同时进行, 多核cpu同时执行
- 并发, 多个任务轮流进行, cpu一个一个的执行
证明 JVM 是多线程的
垃圾回收和main线程间隔执行
public class Demo1_Thread {
public static void main(String[] args) {
for(int i=0; i < 10000000 ;i++){
new Demo();
}
for(int i=0; i < 10000 ; i++){
System.out.println("主线程");
}
}
}
class Demo{
@Override
protected void finalize() throws Throwable {
System.out.println("垃圾被回收了");
}
}
继承Thread 开启一个线程
- 实际run() 方法
- start() 开启线程
public class Demo2_ExtendsThread {
public static void main(String[] args) {
MyThread mt = new MyThread();
// mt.run();
mt.start();
for (int i=0; i <10000 ; i++){
System.out.println(i+"bbbbbbbbbbbbb");
}
}
}
class MyThread extends Thread{
@Override
public void run() {
for(int i=0; i < 10000 ;i++){
System.out.println(i+"aaaaaaaaaaaaaaa");
}
}
}
实际 Runnable 接口的类
- 实际Runnable类, 类作为参数传递给线程, start() 开启线程
public class Demo3_Runnable {
public static void main(String[] args) {
MyRunnable d = new MyRunnable();
Thread t = new Thread(d);
t.start();
for(int i=0; i < 10000 ;i++){
System.out.println(i+"bbbbbbbbbbbbbbb");
}
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for(int i=0; i < 10000 ;i++){
System.out.println(i+"aaa");
}
}
}
多线程的2种区别
- 继承 Thread: 由于子类重写了Thread类的run()方法, 当调用start()时, 直接找子类的run()方法
- 实际 Runnable: 构造函数中传入了Runnable的引用, 成员变量记住了它, start()调用run() 方法时内部判断成员变量Runnable的引用是否为空,
不为空看的Runnable的run(), 运行时是子类的run()方法. - 继承Thread实现简单, 方便使用, 有父类则不能使用这种方法
- 有父类时可以实际Runnable 接口实现多线程, 对继承Thread的补充, 使用时必须获取线程对象, 使用复杂
匿名内类实现多线程的方法
public class Demo4_NoNameThread {
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
for(int i=0; i<100000 ;i++){
System.out.println("aaaaaa");
}
}
}.start();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<10000;i++){
System.out.println("bbbbbbbbbbbbbbbbbbb");
}
}
});
t.start();
}
}
匿名内部类设置线程名字
public class Demo5_ThreadName {
public static void main(String[] args) {
// demo1();
Thread t = new Thread(){
@Override
public void run() {
// this.setName("小明");
System.out.println(this.getName()+"aaaaa");
}
};
t.setName("李明");
t.start();
new Thread(){
@Override
public void run() {
this.setName("小明");
System.out.println(this.getName()+"aaaaa");
}
}.start();
}
private static void demo1() {
new Thread("小明"){
@Override
public void run() {
System.out.println(this.getName()+ "aaaaa");
}
}.start();
new Thread("小红"){
@Override
public void run() {
System.out.println(this.getName()+ "bbbbbb");
}
}.start();
}
}
也可调用setName更改名称 获取本类的引用Thread.currentThread()
public class Demo6_GetName {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
Thread.currentThread().setName("主线程");
System.out.println(Thread.currentThread().getName());
new Thread( new Runnable() {
@Override
public void run() {
System.out.println("dkf"+Thread.currentThread().getName());
}
}).start();
}
}
休眠线程
public class Demo7_ThreadSleep {
public static void main(String[] args) throws InterruptedException {
// demo1();
new Thread(){
@Override
public void run() {
for (int i=0;i<10;i++) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+"a");
}
}
}.start();
new Thread(){
@Override
public void run() {
for (int i=0;i<10;i++) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+"bbbb");
}
}
}.start();
}
private static void demo1() throws InterruptedException {
for (int i=0; i<100;i++){
Thread.sleep(1000);
System.out.println(i);
}
}
}
守护线程
- 守护线程不会单独执行, 其他线程执行完了, 自动结束守护线程
- final void setDaemon(boolean on)
public class Demo8_GudarThread {
public static void main(String[] args) {
Thread t1 = new Thread(){
@Override
public void run() {
for (int i =0;i<2;i++){
System.out.println(getName()+i);
}
}
};
Thread t2 = new Thread(){
@Override
public void run() {
for (int i =0;i<50;i++){
System.out.println(getName()+"aaaaaaaaaaa");
}
}
};
t2.setDaemon(true);
t1.start();
t2.start();
}
}
加入线程
- final void join() throws InterruptedException 插队执行线程
- final void join(long millis) throws InterruptedException 插队执行m毫秒后, 再交其他线程
public class Demo9_ThreadJoin {
public static void main(String[] args) {
Thread t1 = new Thread(){
@Override
public void run() {
for (int i =0;i<100;i++){
System.out.println(getName()+i);
}
}
};
Thread t2 = new Thread(){
@Override
public void run() {
for (int i =0;i<100;i++){
if(i == 2) {
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(getName()+"aaaaaaaaaaa");
}
}
};
t1.start();
t2.start();
}
}
礼让线程, 了解即可
public class Demo10_Yield {
public static void main(String[] args) {
new MyThread2().start();
new MyThread2().start();
}
}
class MyThread2 extends Thread{
@Override
public void run() {
for (int i=0;i<1000;i++) {
if(0 == i%10){
Thread.yield();
}
System.out.println(getName()+" "+i);
}
}
}
线程优先级
- final void setPriority(int newPriority) 设置线程的优先级, 小范围1-10
public class Demo11_Priority {
public static void main(String[] args) {
Thread t = new Thread(){
@Override
public void run() {
for (int i=0;i<100;i++){
System.out.println(getName()+"aaa");
}
}
};
Thread t2 = new Thread(){
@Override
public void run() {
for (int i=0;i<100;i++){
System.out.println(getName()+"bbb");
}
}
};
t2.setPriority(Thread.MIN_PRIORITY);
t.setPriority(Thread.MAX_PRIORITY);
t.start();
t2.start();
}
}
线程同步
- 当多线程执行到一段代码块时, 不希望线程切换其他线程
- synchronized 关键字锁对象到定义一段代码块, 同步代码块
- 锁对象是任意的, 锁对象不能是匿名对象
public class Demo1_Synchronized {
public static void main(String[] args) {
Printer p = new Printer();
new Thread(){
@Override
public void run() {
while (true) {
p.eatApple();
}
}
}.start();
new Thread(){
@Override
public void run() {
while (true) {
p.eatMeet();
}
}
}.start();
}
}
class Printer{
Demo d = new Demo();
public void eatApple(){
synchronized (d) {
System.out.print("a");
System.out.print("a");
System.out.print("a");
System.out.print("a");
System.out.print("a");
System.out.print("a");
System.out.println();
}
}
public void eatMeet(){
synchronized (d) {
System.out.print("b");
System.out.print("b");
System.out.print("b");
System.out.print("b");
System.out.print("b");
System.out.print("b");
System.out.println();
}
}
}
class Demo{}
同步方法
- 非静态方法的锁对象是this
- 静态方法的锁对象是字节码对象
package com.lizicai.sync;
public class Demo2_Syn {
public static void main(String[] args) {
Printer2 p = new Printer2();
new Thread() {
@Override
public void run() {
while (true) {
p.eatApple();
}
}
}.start();
new Thread() {
@Override
public void run() {
while (true) {
p.eatMeet();
}
}
}.start();
}
}
class Printer2{
Demo d = new Demo();
synchronized public void eatApple(){
System.out.print("a");
System.out.print("a");
System.out.print("a");
System.out.print("a");
System.out.print("a");
System.out.print("a");
System.out.println();
}
public void eatMeet(){
synchronized (this) {
System.out.print("b");
System.out.print("b");
System.out.print("b");
System.out.print("b");
System.out.print("b");
System.out.print("b");
System.out.println();
}
}
}
class Demo2{
}
public class Demo3_SynStaticMethod {
public static void main(String[] args) {
Printer3 p = new Printer3();
new Thread() {
@Override
public void run() {
while (true) {
Printer3.eatApple();
}
}
}.start();
new Thread() {
@Override
public void run() {
while (true) {
Printer3.eatMeet();
}
}
}.start();
}
}
class Printer3{
Demo d = new Demo();
synchronized public static void eatApple(){
System.out.print("a");
System.out.print("a");
System.out.print("a");
System.out.print("a");
System.out.print("a");
System.out.print("a");
System.out.println();
}
public static void eatMeet(){
synchronized (Printer3.class) {
System.out.print("b");
System.out.print("b");
System.out.print("b");
System.out.print("b");
System.out.print("b");
System.out.print("b");
System.out.println();
}
}
}
模拟卖票
- 使用唯一对象字节对象作为锁
- 或者使用静态的对象作为锁
public class Demo4_SynSoldTicket {
public static void main(String[] args) {
new Ticket().start();
new Ticket().start();
new Ticket().start();
new Ticket().start();
}
}
class Ticket extends Thread{
private static int tickets = 100;
private static Object obj = new Object();
@Override
public void run() {
while (true){
// synchronized (obj){
synchronized (Ticket.class) {
if( tickets <= 0){
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+"-Ticket"+tickets--);
}
}
}
}
火车站卖票 Runnable接口方式
- 多次启动start()非法
public class Demo5_SynSoldTicket {
public static void main(String[] args) {
Ticket2 tc = new Ticket2();
new Thread(tc).start();
new Thread(tc).start();
new Thread(tc).start();
new Thread(tc).start();
}
}
class Ticket2 implements Runnable{
private int tickets = 100;
@Override
public void run() {
while (true) {
// Ticket2.class 也可
// synchronized (Ticket2.class) {
synchronized (this) {
if( tickets <= 0){
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-Ticket"+tickets--);
}
}
}
}
多线程死锁
- 避免同步代码块嵌套, 容易造成死锁
public class Demo6_SynDead {
private static String s1 = "筷子左";
private static String s2 = "筷子右";
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
while (true){
synchronized (s1){
System.out.println(getName()+"..."+s1+"等待"+s2);
synchronized (s2){
System.out.println(getName()+"...拿到"+s1+s2+"开饭");
}
}
}
}
}.start();
new Thread(){
@Override
public void run() {
while (true){
synchronized (s2){
System.out.println(getName()+"..."+s2+"等待"+s1);
synchronized (s1){
System.out.println(getName()+"...拿到"+s2+s1+"开饭");
}
}
}
}
}.start();
}
}
线程安全的类
- Vector 线程安全的, ArrayList线程不安全
- StringBuffer 线程安全的, StringBuilder 线程不安全的
- Hashtable 线程安全的, HashMap 线程不安全的
- Connections 中有synchronizedList 等方法返回线程安全的列表ArrayList