一、线程和进程

1、线程

注意:多线程。从宏观角度同时执行了多个线程。

从微观角度同一时间只能执行一个线程

      多个线程是竞争关系,抢占cpu资源,否则只能等待。

2、进程和线程的区别:

进程是应用程序,线程是一条执行路径

进程有独立的内存空间,崩溃不会影响其他程序,

线程没有独立的空间,多个线程在同一个进程的空间,可能会影响其他线程

一个进程中,至少有一个线程

3、主线程子线程

主线程:main方法产生的线程,也叫作UI线程。

子线程:除了主线程以外的,也叫工作线程。

4、创建线程的两种方式

1、创建一个类继承Thread

2、重写run方法

3、创建线程对象

4、启动线程

5、Thread.currentThread().getName(),哪个线程调用,名字就是哪个现成的名字

  getName();super调用父类的getName(),被赋值谁的名字,就打印谁的名字

    

main方法:

Test2 test=new Test2("一号窗口");test.start();

    Test2 test2=new Test2("二号窗口");test2.start();



class Test2 extends Thread{

    String name;

    int ticket=10;

     public Test2(String name) {

        super(name);

        this.name = name;

    }

    public void run() {

        while (true) {

            if (ticket>0) {

                ticket--;

                System.out.println(Thread.currentThread().getName()+"还剩下"+ticket);

            }else {

                break;}

        }

    }

共享资源操作相同

1、共享资源类实现Runable接口

2、重写run方法

3、创建共享资源对象

4、创建线程对象,将共享资源对象添加到线程中

5、启动线程

main方法:

Test3 test3=new Test3();

Thread thread=new Thread(test3);

Thread thread2=new Thread(test3);

thread.start();

thread2.start();



class Test3 extends Thread{

    String name;

    int ticket=10;

     public Test2(String name) {

        super(name);

        this.name = name;

    }

    public void run() {

        while (true) {

            if (ticket>0) {

                ticket--;

                System.out.println(Thread.currentThread().getName()+"还剩下"+ticket);

            }else {

                break;}

        }

    }

贡献资源操作不相同

1、贡献资源作为一个单独的类

2、由多个操作去实现Runable接口

3、把共享资源作为多个操作类的属性

4、创建线程对象,将共享资源对象添加到线程中

5、启动线程

main方法:

Card card=new Card();

Boyfriend boyfriend=new Boyfriend(card);

Girlfriend girlfriend=new Girlfriend(card);

Thread thread=new Thread(boyfriend);

Thread thread2=new Thread(girlfriend);

thread.start();

thread2.start();

class Card{

    double money;

}

class Boyfriend implements Runnable{

    Card card;

    public Boyfriend(Card card){

        this.card=card;

    }

    @Override

    public void run() {

    // TODO Auto-generated method stub

        for (int i = 0; i < 5; i++) {

            card.money+=500;

            System.out.println(Thread.currentThread().getName()+"存500-剩余金额"+card.money);

        }

    }

}

class Girlfriend implements Runnable{

    Card card;

    public Girlfriend(Card card){

        this.card=card;

    }

    @Override

    public void run() {

    // TODO Auto-generated method stub

        for (int i = 0; i < 5; i++) {

            card.money-=500;

            System.out.println(Thread.currentThread().getName()+"取500,剩余金额"+card.money);

        }

    }

}

5、run和start的区别

run没有开辟新的栈空间,没有新线程,都是主线程在执行

start开辟了新的栈空间,在新的栈空间启动run()方法
6、线程的调度

setPriority();分配优先级,默认5,最低1,最高10

.join();插队,阻塞指定的线程等到另一个线程完成以后再继续执行

.sleep();需要设置睡眠时间

.yield();礼让,当执行到这个方法时,会让出cpu时间,立马变成可执行状态

sleep和pield的区别:

sleep                 yeild

    线程进入被阻塞的状态   线程转入暂停执行的状态

(没有其他线程运行)等待指定的时间再运行 马上恢复执行的状态

其他线程的执行机会是均等的   将优先级或更高的线程运行

7、打断线程的终止方式

1、用标记,当终止线程时,会执行完run方法

2、stop()方法,不建议使用,会执行不到特定的代码

3、interrupt(),只能中断正在休眠的线程,通过抛异常的方法中断线程的终止。

InputStream inputStream=System.in;

int m=inputStream.read();

myThread2.interrupt();//通过外界输入打断

8、线程是五种状态

新建 就绪 执行 死亡 阻塞
二、同步

发生在两个以两个以上的线程中

解决代码的重复问题

优点:提高了线程中数据的安全性

缺点:降低了执行效率

1、同步代码块

synchronized(锁){同步代码块}

注意:锁分任意锁和互斥锁,锁是对象,琐是唯一的。

2、同步方法

public synchroinzed 返回值类型 方法名(){同步代码}

3、在共享资源中:

线程操作相同,琐是this

    synchronized (this) {// 同步代码块,包含同步代码块。任意锁,互斥锁。

        if (ticket > 0) {

            System.out.println(Thread.currentThread().getName() + "---" + ticket--);

        } else {

            break;

        }

    }

线程操作不相同,琐是共享资源对象

    synchronized (card) {

        card.setMoney(card.getMoney() + 1000);

        System.out.println("Boy+1000---" + card.getMoney());

    }

4、在同步方法中:

共享资源,线程操作相同,资源类中的锁是this

共享资源,线程操作不相同,资源类中的锁也是this

    public synchronized void input(){

        money+=100;

        System.out.println("input+100----"+money);



}

5、在静态方法中同步:懒汉式

同步代码块,琐是类.class

同步方法,锁也是类.class

public  static LazyInstance getInstance(){

    if (instance==null) {

        synchronized (LazyInstance.class) {

            if (instance==null) {

                try {

                    Thread.sleep(1000);

                } catch (InterruptedException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

                }

                instance=new LazyInstance();

            }

        System.err.println(instance.hashCode());

        }



        }       

    return instance;

}

三、经典例子:生产者消费者

面包类:class Bread{属性和构造方法}

超市类:class Market{

Bread[] breads=new Bread[];//超市里有面包数组

    int index=-1;//一开始没有面包,下标为-1;

    public synchronized void sale(){

        if(index<=-1){如果没有没有面包,就等待添加

            this.wait();

            }

        如果有面包,就打印面包信息

        System.out.println("消费面包"+breads[index].id+breads[index].name+breads[index].price);

        index--;//面包减少一个

        this.notify();唤醒添加线程

        }

    public synchronized vide add(Bread bread){

        if(index>=4){

            this.wait();

            }

        indenx++;//面包下标+1,存入下一面包位置中

        breads[index]=bread;//给数组中的面包赋值

        System.out.println("添加面包"+breads[index].id+breads[index].name+breads[index].price); 

        this.notify();//唤醒销售线程

        }

工厂类:实现Runnable接口:

将超市类作为属性

    添加构造方法

    重写run方法,调用超市类add方法

顾客类:实现Runnable接口:

将超市类作为属性

    添加构造方法

    重写run方法,调用超市类sale方法