欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

线程的基本了解

程序员文章站 2022-12-29 15:52:15
1、线程的实现方式 线程有两种实现方式,分别为继承Thread、实现Runnable接口。差异性:实现方式避免了类的继承单一性,且对于多个线程同时访问同一个资源时更便捷。 (1)继承Thread class TestThread extends Thread { @Override public v ......

1、线程的实现方式

线程有两种实现方式,分别为继承thread、实现runnable接口。差异性:实现方式避免了类的继承单一性,且对于多个线程同时访问同一个资源时更便捷。

(1)继承thread

线程的基本了解
class testthread extends thread {
    @override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            system.out.println(thread.currentthread().getname()+":"+i);
        }
    }
}

public class testthreadmethod {
    public static void main(string[] args) {
        testthread th1 = new testthread();
        th1.setname("testthread");
        th1.start();
    }
}
view code

(2)实现runnable接口

线程的基本了解
class testrunnable implements runnable{
    @override
    public void run() {
        for (int i=1; i <= 100; i++) {
            system.out.println(thread.currentthread().getname() + ":" + i);
        }
    }
}

public class testmain {
    public static void main(string[] args) {
        testrunnable tr = new testrunnable();
        thread th1 = new thread(tr, "th1");
        thread th2 = new thread(tr, "th2");
        th1.start();
        th2.start();
    }
}
view code

(3)线程的生命周期

线程的基本了解

2、线程的常用方法

start():线程的开启。同一个线程在结束时只能开启一次,否则报错。

setname():设置当前线程的名称。

getname():获取当前线程的名称。

currentthread():获取当前线程的对象。

priority():线程的级别。静态值有,0/5(默认)/10。值越高,代表争夺cpu的使用权的几率越大,但不是绝对。

yield():线程让步。当前线程a调用yield()方法时,释放cpu的使用权,重新与其他线程b争夺cpu的使用权。

join():线程加入。在a线程中,调用b线程的join方法时,a线程的程序等待b线程的程序执行完才能继续执行a线程。

sleep():线程睡眠。当线程执行该方法时,进入设置的睡眠时间后继续执行程序。

isalive():线程是否在活动,返回值为boolean。

wait():线程等待。必须在同步方法中使用。

notify()/notifyall():线程唤醒,与wait()结合使用,用于线程通信。

注意:(1)线程在同步时,wait()会释放锁,而join()与sleep()方法不会释放锁。

   (2)wait()、notify()、notifyall()严格来说不算线程中的方法,这三个方法是定义在object对象中。

线程的基本了解
class testthread extends thread {
    @override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            system.out.println(thread.currentthread().getname()+":"+i);
        }
    }
}

public class testthreadmethod {
    public static void main(string[] args) {
        testthread th1 = new testthread();
        th1.setname("testthread");
        th1.setpriority(thread.max_priority);
        th1.start();
        
        thread.currentthread().setname("=======mainthread");
        for (int i = 0; i <= 100; i++) {
            system.out.println(thread.currentthread().getname() + ":" + i);
            if (i % 10 == 0) {
                thread.yield();
            }
            if (i == 20) {
                try {
                    th1.join();
                    system.out.println(th1.isalive());
                    th1.start();
                } catch (interruptedexception e) {
                    e.printstacktrace();
                }
            }
        }
    }
}
view code

3、线程的同步

线程的同步分为两种:同步代码块和同步方法块。

线程的基本了解
class testthread extends thread {
    static int ticket = 100;
    static object obj = new object();
    
    @override
    public void run() {
        /*1、同步代码块时,只能同步需要的代码块,其余无关代码块不行,会影响同步;
         * 2、同步监视器用this,代表当前对象,此时继承方式,对象是多个,所以无法同步;
         * 此两种情况出现重复输出情况,如下的this情况
         */
        /*synchronized (this) {
            while(true) {
                    try {
                        thread.currentthread().sleep(100);
                    } catch (interruptedexception e) {
                        // todao auto-generated catch block
                        e.printstacktrace();
                    }
                    if (ticket <= 0) {
                        break;
                    }
                    system.out.println(thread.currentthread().getname() + "窗口:" +ticket--);
                }
            }*/
            while(true) {
                synchronized (obj) {//obj充当锁时必须是静态的,否则多个对象代表的锁是各自的。
                    try {
                        thread.currentthread().sleep(100);
                    } catch (interruptedexception e) {
                        e.printstacktrace();
                    }
                    if (ticket <= 0) {
                        break;
                    }
                    system.out.println(thread.currentthread().getname() + "窗口:" +ticket--);
                }
            }
    }
}

public class testmain {
    public static void main(string[] args) {
        testthread th1 = new testthread();
        testthread th2 = new testthread();
        th1.setname("th1");
        th2.setname("th2");
        th1.start();
        th2.start();
    }
}
view code
线程的基本了解
class testthread implements runnable {
    int ticket = 100;
    @override
    public void run() {
        while(true) {
            importnum();
        }
    }
    /**
     * 同步方法块时,同步锁为当前对象.所以方法的类必须是同一个对象
     */
    private synchronized void importnum() {
        if (ticket <= 0) {
            return;
        }
        system.out.println(thread.currentthread().getname() + "窗口:" + ticket--);
    }
}

public class testmain {
    public static void main(string[] args) {
        testthread th = new testthread();
        thread th1 = new thread(th, "th1");
        thread th2 = new thread(th, "th2");
        
        th1.start();
        th2.start();
    }
}
view code

注:同步在thread与runnable两种方式的实现中有很大的区别,详见上例。

拓展示例:

线程的基本了解
class singleton {
    private singleton() {
        
    }
    public static singleton instance = null;
    
    public static singleton getsingleton() {
        /**
         *     原程序直接判断,创建实例,返回。在多线程中,存在线程安全问题,会创建多个singleton;
         * 开发中为避免这情况发生,采用下面同步的实现方式。
         */
        /**
            if (instance == null) {
                instance = new singleton();
            }
            return instance;
        */
        if (instance == null) {//提高同步效率,后面访问方法的对象,无需再次等待
            synchronized(singleton.class) {//采用类本身的对象来充当锁
                if (instance == null) {
                    instance = new singleton();
                }
            }
        }
        return instance;
    }
}

public class testmain {
    public static void main(string[] args) {
        
        singleton st1 = singleton.getsingleton();
        singleton st2 = singleton.getsingleton();
    }
}
view code

4、线程的死锁

死锁:当两个线程同时需要对方手中的锁时,各自都在等对方放弃手中的锁,而使程序无限期的等待下去,称为死锁。

线程的基本了解
public class testmain {
    public static void main(string[] args) {
        
        stringbuffer sb1 = new stringbuffer();
        stringbuffer sb2 = new stringbuffer();
        
        new thread(){
            public void run() {
                
                synchronized(sb1) {
                    sb1.append("a");
                    try {
                        thread.currentthread().sleep(10);
                    } catch (interruptedexception e) {
                        e.printstacktrace();
                    }
                    synchronized(sb2) {
                        sb2.append("b");
                        system.out.println("sb1:" + sb1.tostring());
                        system.out.println("sb2:" + sb2.tostring());
                    }
                }
                
            };
        }.start();
        
        new thread(){
            public void run() {
                synchronized(sb2) {
                    sb2.append("c");
                    try {
                        thread.currentthread().sleep(10);
                    } catch (interruptedexception e) {
                        e.printstacktrace();
                    }
                    synchronized(sb1) {
                        sb1.append("d");
                        system.out.println("sb1:" + sb1.tostring());
                        system.out.println("sb2:" + sb2.tostring());
                    }
                }
            };
        }.start();
    }
}
view code

上述例子中,第一个线程执行第一个同步块代码后,进行睡眠,握住sb1的锁;此时第二个线程可能已经开启运行,获取sb2的锁,进行同步代码块方法,进行睡眠。之后第一个线程睡眠时间过后要进行第二个同步代码块的执行,这时sb2的锁握在了第二个线程,而第二个线程在醒来后要获取第二块同步方法的锁时,这时的锁在第一个线程中。两个线程同时在等待对方释放手中的锁,导致了死锁的出现。

5、线程的通信

线程的基本了解
/**
 * 生产者 --> 店员(数量最多存放20) --> 消费者
 *
 */

class clerk {
    int num;
    public synchronized void addproduct() {
        if (num >= 20) {
            try {
                wait();
            } catch (interruptedexception e) {
                // todo auto-generated catch block
                e.printstacktrace();
            }
        }
        notifyall();
        num++;
        
        system.out.println(thread.currentthread().getname() + ":" + num);
    }
    public synchronized void consume() {
        if (num == 0) {
            try {
                wait();
            } catch (interruptedexception e) {
                // todo auto-generated catch block
                e.printstacktrace();
            }
        }
        
        notifyall();
        system.out.println(thread.currentthread().getname() + ":" + num);
        num--;
    }
}

class customer implements runnable {
    clerk clerk;
    
    public customer(clerk clerk) {
        this.clerk = clerk;
    }
    
    public void run() {
        while(true) {
            try {
                thread.currentthread().sleep(10);
            } catch (interruptedexception e) {
                e.printstacktrace();
            }
            clerk.consume();
        }
    }
}

class producer implements runnable {
    clerk clerk;
    
    public producer(clerk clerk) {
        this.clerk = clerk;
    }
    
    public void run() {
        while(true) {
            try {
                thread.currentthread().sleep(10);
            } catch (interruptedexception e) {
                e.printstacktrace();
            }
            clerk.addproduct();
        }
    }
}

public class testmain {
    public static void main(string[] args) {
        clerk clerk = new clerk();
        customer c1 = new customer(clerk);
        producer p1 = new producer(clerk);
        thread th2 = new thread(p1, "生产者");
        thread th1 = new thread(c1, "消费者");
        th2.start();
        th1.start();
    }
}
view code