java多线程编程基础(配合实例)

时间:2023-02-16 12:58:52

1、多线程的实现

在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。
1)直接继承Thread的类来说,代码大致框架是:
class 类名 extends Thread{
方法1;
方法2;

public void run(){
// other code…
}
属性1;
属性2;

}
class hello extends Thread {
 
    public hello() {
 
    }
 
    public hello(String name) {
        this.name = name;
    }
 
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name + "运行     " + i);
        }
    }
 
    public static void main(String[] args) {
        hello h1=new hello("A");
        hello h2=new hello("B");
        h1.start();
        h2.start();
    }
 
    private String name;
}

2)通过实现Runnable接口,大致框架是:
class 类名 implements Runnable{
方法1;
方法2;

public void run(){
// other code…
}
属性1;
属性2;

}
class hello implements Runnable {
 
    public hello() {
 
    }
 
    public hello(String name) {
        this.name = name;
    }
 
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name + "运行     " + i);
        }
    }
 
    public static void main(String[] args) {
        hello h1=new hello("线程A");
        Thread demo= new Thread(h1);
        hello h2=new hello("线程B");
        Thread demo1=new Thread(h2);
        demo.start();
        demo1.start();
    }
 
    private String name;
}

注意:
因为需要用到CPU的资源,所以每次的运行结果基本是都不一样的。
线程如果我们没有指定名字的话,系统自动提供线程名字。
关于选择继承Thread还是实现Runnable接口,其实Thread也是实现Runnable接口的:

class Thread implements Runnable {
    //…
public void run() {
        if (target != null) {
             target.run();
        }
    }
}

2、Thread和Runnable的区别:
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
(注意只是资源共享,和是否需要同步是两个概念)
class hello extends Thread {
    public void run() {
        for (int i = 0; i < 7; i++) {
            if (count > 0) {
                System.out.println("count= " + count--);
            }
        }
    }
 
    public static void main(String[] args) {
        hello h1 = new hello();
        hello h2 = new hello();
        hello h3 = new hello();
        h1.start();
        h2.start();
        h3.start();
    }
 
    private int count = 5;
}

class MyThread implements Runnable{
 
    private int ticket = 5;  //5张票
 
    public void run() {
        for (int i=0; i<=20; i++) {
            if (this.ticket > 0) {
                System.out.println(Thread.currentThread().getName()+ "正在卖票"+this.ticket--);
            }
        }
    }
}

public class lzwCode {
     
    public static void main(String [] args) {
        MyThread my = new MyThread();
        new Thread(my, "1号窗口").start();
        new Thread(my, "2号窗口").start();
        new Thread(my, "3号窗口").start();
    }
}

总结一下:
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。


3、线程的强制执行:
class hello implements Runnable {
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName());
        }
    }
 
    public static void main(String[] args) {
        hello he = new hello();
        Thread demo = new Thread(he,"线程");
        demo.start();
        for(int i=0;i<50;++i){
            if(i>10){
                try{
                    demo.join();  //强制执行demo
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
            System.out.println("main 线程执行-->"+i);
        }
    }
}

【运行的结果】:
main 线程执行-->0

main 线程执行-->1

main 线程执行-->2

main 线程执行-->3

main 线程执行-->4

main 线程执行-->5

main 线程执行-->6

main 线程执行-->7

main 线程执行-->8

main 线程执行-->9

main 线程执行-->10

线程

线程

线程

main 线程执行-->11

main 线程执行-->12

main 线程执行-->13

...

4、线程的休眠:
class hello implements Runnable {
    public void run() {
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + i);
        }
    }
 
    public static void main(String[] args) {
        hello he = new hello();
        Thread demo = new Thread(he, "线程");
        demo.start();
    }
}

【运行结果】:(结果每隔2s输出一个)

线程0

线程1

线程2

注意:这里sleep和wait的关键区别,sleep和wait都可以阻塞线程,但是sleep不会释放对象资源,比如对象锁等,
但是wait会释放它占用的该对象的所有资源。

5、线程的中断:
class hello implements Runnable {
    public void run() {
        System.out.println("执行run方法");
        try {
            Thread.sleep(10000);
            System.out.println("线程完成休眠");
        } catch (Exception e) {
            System.out.println("休眠被打断");
            return;  //返回到程序的调用处
        }
        System.out.println("线程正常终止");
    }
 
    public static void main(String[] args) {
        hello he = new hello();
        Thread demo = new Thread(he, "线程");
        demo.start();
        try{
            Thread.sleep(2000);
        }catch (Exception e) {
            e.printStackTrace();
        }
        demo.interrupt(); //2s后中断线程
    }
}

【运行结果】:

执行run方法

休眠被打断

6、线程的优先级:
class hello implements Runnable {
    public void run() {
        for(int i=0;i<5;++i){
            System.out.println(Thread.currentThread().getName()+"运行"+i);
        }
    }
 
    public static void main(String[] args) {
        Thread h1=new Thread(new hello(),"A");
        Thread h2=new Thread(new hello(),"B");
        Thread h3=new Thread(new hello(),"C");
        h1.setPriority(8);
        h2.setPriority(2);
        h3.setPriority(6);
        h1.start();
        h2.start();
        h3.start();
         
    }
}

【运行结果】:

A运行0

A运行1

A运行2

A运行3

A运行4

B运行0

C运行0

C运行1

C运行2

C运行3

C运行4

B运行1

B运行2

B运行3

B运行4

注意:不要误以为优先级越高就一定先执行,只能说线程调度的时候,分配cpu给它的概率会更大而已。主线程的优先级是5.

7、线程的礼让:
在线程操作中,也可以使用yield()方法,将一个线程的操作暂时交给其他线程执行。
class hello implements Runnable {
    public void run() {
        for(int i=0;i<10;++i){
            System.out.println(Thread.currentThread().getName()+ "运行"+i);
            if(i==3){
                System.out.println(Thread.currentThread().getName()+ "线程的礼让");
                Thread.currentThread().yield();
            }
        }
    }
 
    public static void main(String[] args) {
        Thread h1=new Thread(new hello(),"A");
        Thread h2=new Thread(new hello(),"B");
        Thread h3=new Thread(new hello(),"C");
        h1.start();
        h2.start();
        h3.start();
    }
}

【运行结果】:
A运行0
A运行1
A运行2
A运行3
A线程的礼让
C运行0
C运行1
C运行2
C运行3
C线程的礼让
A运行4
A运行5
A运行6
A运行7
A运行8
A运行9
A运行10
A运行11
A运行12
A运行13
A运行14
A运行15
A运行16
A运行17
A运行18
A运行19
C运行4
C运行5
C运行6
C运行7
C运行8
C运行9
C运行10
C运行11
C运行12
C运行13
C运行14
C运行15
C运行16
C运行17
C运行18
C运行19
B运行0
B运行1
B运行2
B运行3
B线程的礼让
B运行4
B运行5
B运行6
B运行7
B运行8
B运行9
B运行10
B运行11
B运行12
B运行13
B运行14
B运行15
B运行16
B运行17
B运行18
B运行19

8、同步和死锁:
class hello implements Runnable {
    public void run() {
        for(int i=0;i<10;++i){
            if(count>0){
                try{
                    Thread.sleep(1000);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println(count--);
            }
        }
    }
 
    public static void main(String[] args) {
        hello he=new hello();
        Thread h1=new Thread(he);
        Thread h2=new Thread(he);
        Thread h3=new Thread(he);
        h1.start();
        h2.start();
        h3.start();
    }
    private int count=5;
}

【运行结果】:
5

4

3

2

1

0

-1

这里出现了-1,显然这个是错的。应该票数不能为负值。如果想解决这种问题,就需要使用同步。
所谓同步就是在统一时间段中只有有一个线程运行,其他的线程必须等到这个线程结束之后才能继续执行。
采用同步的话,可以使用同步代码块和同步方法两种来完成。

1)同步代码块
语法格式:
synchronized(同步对象){
 //需要同步的代码
}

一般都把当前对象this作为同步对象。
class hello implements Runnable {
    public void run() {
        for(int i=0;i<10;++i){
            synchronized (this) {
                if(count>0){
                    try{
                        Thread.sleep(1000);
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                    System.out.println(count--);
                }
            }
        }
    }
 
    public static void main(String[] args) {
        hello he=new hello();
        Thread h1=new Thread(he);
        Thread h2=new Thread(he);
        Thread h3=new Thread(he);
        h1.start();
        h2.start();
        h3.start();
    }
    private int count=5;
}

【运行结果】:(每一秒输出一个结果)
5

4

3

2

1

2)同步方法
语法格式为synchronized 方法返回类型方法名(参数列表){
    // 其他代码
}
class hello implements Runnable {
    public void run() {
        for (int i = 0; i < 10; ++i) {
            sale();
        }
    }
 
    public synchronized void sale() {
        if (count > 0) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(count--);
        }
    }
 
    public static void main(String[] args) {
        hello he = new hello();
        Thread h1 = new Thread(he);
        Thread h2 = new Thread(he);
        Thread h3 = new Thread(he);
        h1.start();
        h2.start();
        h3.start();
    }
 
    private int count = 5;
}

【运行结果】(每秒输出一个)
5

4

3

2

1

注意:当多个线程共享一个资源的时候需要进行同步,但是过多的同步可能导致死锁。


参考:http://www.cnblogs.com/rollenholt/archive/2011/08/28/2156357.html