java基础 我的线程初次学习

线程的基本概念:
    线程是一个程序内部顺序控制流
线程与进程的区别:
  • 每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较开销
  • 线程可以看成轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小
  • 多进程:在操作系统中能同时运行多个任务(程序)
  • 多线程:在同意应用程序中有多个顺序流同时执行


Java的线程是通过java.lang.Tread类来实现的

VM(Java虚拟机)启动时会有一个由主方法(public static void main(){})所定义的线程。

可以通过创建Tread的实例来创建新的线程。
每个线程都是通过某个特定Tread对象所对应的方法run()来完成其操作的,方法run()成为线程体
通过调用Thead类的start()方法启动一个线程


java基础 我的线程初次学习

线程的创建和启动
    有两种方式创建新的线程。
    第一种:
  • 定义线程类实现Runnable接口
  • Thread myTread = new Thread(target)  //target为Runnable接口类型.
  • Runnable中只有一个方法:public void run();//用以定义线程运行体
  • 使用Runnable接口可以为多个线程提供共享的数据。
  • 在实现Runnable接口的类的run方法定义中可以使用Tread的静态方法:public static Thread currentThread()获取当前线程的引用。
public class TestThread1{
    public static void main(String[] args){
        Runner1 r = new Runner1();
        Thread m = new Thread(r);
        m.start();
        for(int i=1;i<=100;i++){
            System.out.println("MainThread i: "+i);
        }
    }
}

class Runner1 implements Runnable{
    public void run()
    {
        for(int i=1;i<=100;i++){
            System.out.println("Runner1 i: "+i);
        }
    }
}


第二种:
  • 可以定义一个Thread的子类并重写其run方法如:
class MyThread extends Thread{
    public void run()
    }
 }
  • 然后生成该类的对象:
    • MyThread myThread=new MyTread(...)
public class TestThread1{
    public static void main(String[] args){
        Runner1 r = new Runner1();
        //Thread m = new Thread(r);
        r.start();
        for(int i=1;i<=100;i++){
            System.out.println("MainThread i: "+i);
        }
    }
}

class Runner1 extends Thread{
    public void run()
    {
        for(int i=1;i<=100;i++){
            System.out.println("Runner1 i: "+i);
        }
    }
}

注意:尽量能使用implements Runnable接口就尽量使用接口


线程状态:
线程控制基本方法
方法
功能
isAlive() 判断线程是否还“活着”,即线程是否还未终止。
getPriority() 获得线程的优先级数值。
setPriority() 设置线程的优先级数值。
Thread.sleep() 将当前线程睡眠指定毫秒数。
join() 调用某线程的该方法,将当前线程与该线程“合并”,即等待该线程结束,再恢复当前线程的运行。
yield() 让出CPU,当前线程进入就绪队列等待调度。
wait() 当前线程进入对象的wait pool
notify()/
notifyAll()
唤醒对象的wait pool中的一个/所有等待线程

sleep方法:
  •     可以调用Thread的静态方法:
    •  public static void sleep(long millis) throws InterruptedException(使得当前线程休眠,暂时停止执行millis毫秒)
  • 由于是静态方法,sleep可以由类名直接调用:Thread.sleep()
//每隔一秒钟打印时间,主函数睡眠10秒后打断run1这个类使得它停止
import java.util.*; //调用Date()
public class TestInterrupt{
    public static void main(String []args){
        run1 r = new run1();
        r.start();
        try{
            Thread.sleep(10000);
        }catch(InterruptedException e){}
        r.interrupt();
    }
}
class run1 extends Thread{
    public void run(){
        while(true){
            System.out.println("---"+new Date()+"---");
            try{
                sleep(1000);
            }catch(InterruptedException e){
                return;
            }
        }
    }
}


join方法:
  • 合并某个线程

public class TestJoin{
    public static void main(String[] args){
        MyThread2 t2 = new MyThread2("t2");
        t2.start();
        try{
            t2.join();            //会先执行完t2,才会执行下面的代码
        }catch(InterruptedException e){return;}
        for(int i = 0;i<=10;i++){
            System.out.println("Main: "+i);
        }
    }
}
class MyThread2 extends Thread{
    MyThread2(String s){
        super(s);
    }
    public void run(){
        for(int i = 0;i<=10;i++){
            try{
                sleep(1000);
            }catch(InterruptedException e){return;}
            
        System.out.println(getName()+" :"+i);
        }
    }
}


yield方法
  • 让出CPU给其他线程执行的机会
public class TestYield{
    public static void main(String[] args){
        MyThread3 t1 = new MyThread3("t1");
        MyThread3 t2 = new MyThread3("t2");
        t1.start();
        t2.start();
    }
}
class MyThread3 extends Thread{
    MyThread3(String s){
        super(s);
    }
    public void run(){
        for(int i=0;i<100;i++){
            System.out.println(getName()+": "+i);
            if(i%10==0){
                yield();        暂时让其他线程执行多一些
            }
        }
    }
}


线程的优先级:
  • 线程的优先级用数字表示,范围从1到10,一个线程的缺省优先级是5.
    • Thread.MIN_PRIORITY=1
    • Thread.MAX_PRIORITY=10
    • Thread.NORM_PRIORITY=5
  • 使用下述线程的方法获得或设置线程对象的优先级。
    • int getPriority();
    • void setPriority(int newPriority);
public class TestPriority{
    public static void main(String[] args){
        T1 t1 = new T1();
        T2 t2 = new T2();
        Thread tt1  = new Thread(t1);
        Thread tt2  = new Thread(t2);
        tt1.setPriority(Thread.NORM_PRIORITY +3);
        tt1.start();
        tt2.start();
    }
}
class T1 implements Runnable{
    public void run(){
        for(int i=0;i<1000;i++){
            System.out.println("T1: "+i);
        }
    }
}
class T2 implements Runnable{
    public void run(){
        for(int i=0;i<1000;i++){
            System.out.println("----T2: "+i);
        }
    }
}



正确的停止线程的方法:
public class TestThread4{
    public static void main(String[] args){
        Runner3 r = new Runner3();
        Thread t = new Thread(r);
        t.start();
        for(int i=0;i<100;i++){
            System.out.println("in thread main i="+i);
        }
        System.out.println("Thread main is over");
        r.shutDown();
    }
}
class Runner3 implements Runnable{
    private boolean flag = true;
    
    public void run(){
        int i=0;
        while(flag==true){
            i++;
            System.out.println(" "+i);
        }
    }
    public void shutDown(){
        flag=false;
    }
}


线程同步:
当某个对象被synchronized修饰时,表明该对象在任一时刻只能由一个线程访问(通俗来讲,该这里被锁住了)
public class TestSync implements Runnable{
    Timer timer = new Timer();
    public static void main(String[] args){
        TestSync test = new Thread(test);
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test);
        t1.start();
        t2.start();
    }
    public void run(){
        timer.add(Thread.currentThread().getName());
    }
}
class Timer{
    private static int num=0;
    public void add(String name){
      锁的第一种写法:  synchronized (this){
            num++;
            try{Thread.sleep(1);}
            catch(InterruptedException e){}
            System.out.println(name+", 你是第"+num+"个使用timer的线程");
        }
    }
}
class Timer{
    private static int num=0;
   锁的第二种写法: public  synchronized void add(String name){
            num++;
            try{Thread.sleep(1);}
            catch(InterruptedException e){}
            System.out.println(name+", 你是第"+num+"个使用timer的线程");
    }
}
如果高亮的地方被注释,也就是没有加锁,输出结果是两个 :你是第2个使用timer的线程
否则被锁住才会输出:你是1个使用timer的线程\n 你是第2个使用timer的线程

注意:死锁(互斥锁)
public class TestDeadLock implements Runnable{
    public int flag=1;
    static Object o1 =new Object(),o2 = new Object();
    public void run(){
        System.out.println("flag="+flag);
        if(flag==1){
            synchronized(o1){
                try{
                    Thread.sleep(500);
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
            synchronized(o2){
                System.out.println("1");
            }
        }
        if(flag==0){
            synchronized(o2){
                try{
                    Thread.sleep(500);
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
            synchronized(o1){
                System.out.println("0");
            }
        }
    }
}
一些问题:
提问:打印的结果是多少
public class TT implements Runnable{
    int b =100;
    
    public synchronized void m1() throws Exception{
        b=1000;
        Thread.sleep(5000);
        System.out.println("b= "+b);
    }
    
    public void m2(){
        System.out.println(b);
    }
    public void run(){
        try{
            m1();
        }    catch(Exception e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws Exception{
        TT tt = new TT();
        Thread t = new Thread(tt);
        t.start();
        Thread.sleep(1000);
        tt.m2();
        
        System.out.println(tt.b);
    }
}
结果:1000\n  1000

public class TT implements Runnable{
    int b =100;
    
    public synchronized void m1() throws Exception{  //只是保证只有一个线程使用这个方法,其他的方法依然可以使用
        b=1000;
        Thread.sleep(5000);
        System.out.println("b= "+b);
    }
    
    public void m2()throws Exception{
        Thread.sleep(2500);
        b=2000;
    }
    public void run(){
        try{
            m1();
        }    catch(Exception e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws Exception{
        TT tt = new TT();
        Thread t = new Thread(tt);
        t.start();
        tt.m2();
        
    }
}
结果:2000 
public class TT implements Runnable{
    int b =100;
    
    public synchronized void m1() throws Exception{
        b=1000;
        Thread.sleep(5000);
        System.out.println("b= "+b);
    }
    
    public synchronized void m2()throws Exception{
        Thread.sleep(2500);
        b=2000;
    }
    public void run(){
        try{
            m1();
        }    catch(Exception e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws Exception{
        TT tt = new TT();
        Thread t = new Thread(tt);
        t.start();
        tt.m2();
        System.out.println(tt.b);
        
    }
}
结果 :1000/n b=1000


notify不能叫醒自己!!!
经典生产包子 消费包子同时进行的问题。考察到了wait(),notify(),sychronized等语法
//一个线程生产包子,一个线程消费包子
//注意栈的用到
public class ProducerConsumer{
    public static void main(String[] args){
        wtStack ww = new wtStack();
        producer p1 = new producer(ww);
        consumer c1 = new consumer(ww);
        Thread p = new Thread(p1);
        Thread c = new Thread(c1);
        p.start();
        c.start();
    }
}
class wotou{
    int id;
    wotou(int id){
        this.id=id;
    }
    public String toString(){
        return "wotou's id :"+id;
    }
}
class wtStack{
    int index=0;
    wotou[] wotous= new wotou[6];
    
    public synchronized void push(wotou ww){
        while(index==wotous.length){
            try{
                this.wait();          //使得当前的线程暂停
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
        this.notify();               //唤醒一个其他的wait的线程 如果是notifyAll()则为唤醒其他所有的wait线程
        wotous[index]=ww;
        index++;
    }
    
    public synchronized wotou pop(){
        while(index==0){
            try{
                this.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
        this.notify();
        index--;
        return wotous[index];
    }
}
class producer implements Runnable{
    wtStack ww = null;
    producer(wtStack ww){
        this.ww=ww;
    }
    public void run(){
        for(int i=0;i<20;i++){
            wotou temp = new wotou(i);
            System.out.println("生产了:"+temp);
            ww.push(temp);
            /*try{
                Thread.sleep((int)(Math.random()*20));
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            */
        }
    }
}
class consumer implements Runnable{
    wtStack ww = null;
    consumer(wtStack ww){
        this.ww=ww;
    }
    public void run(){
        for(int i=0;i<20;i++){
            wotou temp = null;
            temp=ww.pop();
            System.out.println("消费了"+temp);
        }
        /*try{
                Thread.sleep((int)(Math.random()*20));
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            */
    }
}