day07

JavaDay07总结

1、进程运行中的应用程序,每个进程都有自己独立的地址空间(内存空间)eg.点击一个桌面的浏览器,操作系统为该进程分配一个独立的内存空间,当用户再次点击时,又启动一个进程,操作系统将为新的进程分配新的独立的内存空间。
线程进程中的一个实体,是被系统独立调度和分派的基本单位,线程不拥有系统资源,只拥有一点在运行中必不可少的资源,但他可与同属于一个进程的其他线程共享进程所拥有的全部资源一个线程可以创建和撤销另一个线程,同一进程中的多个线程之间可以并发进行。线程有五个基本状态:新建、就绪、运行、阻塞、死亡。
只要应用程序涉及到并发,就离不开多线程编程
1)线程是轻量级的进程 2)线程没有独立的线程空间 3)线程是由进程创建的(寄生在进程)4)一个进程可以有多个线程(多线程编程)5)五种状态
这里写图片描述
一个类当作线程来使用的两种方法:1)继承Thread类,并重写run函数 2)实现Runnable接口,并重写run函数
线程--继承Thread和实现Runnable的区别
1)尽可能使用实现Runnable接口的方式来创建线程
2)在使用Thread时只需new一个实例。调用start()即可启动一个线程
3)在使用Runnable时需先new一个实现Runnable的实例,之后再用Thread调用

/*
作者:mys
功能:继承Thread类的方式使用线程
日期:2018/7/21
 */
public class Demo5 {
    public static void main(String []args){
        Cat1 cat=new Cat1();
        //启动线程,导致run函数的运行
        cat.start();
    }
}
class Cat1 extends Thread{
    int times=0;
    //重写run函数
    public void run(){
        while(true) {
            try {
                //休眠1s  1000表示1ms
                //sleep让线程进入到Blocked状态,并释放资源
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            times++;
            System.out.println("Hello word");
            if(times==10) {
                break;
            }
        }
    }
}

/*
功能:实现Runnable的方式使用线程
 */
public class Demo5_1 {
    public static void main(String []args){
        //注意启动
          Dog dog=new Dog();
          //创建一个Thread对象
          Thread thread=new Thread(dog);
          thread.start();
    }
}

/*
功能:两个线程同时进行
 */
public class Demo6 {
    public static void main(String []args){
        //创建两个对象
        Monkey mon=new Monkey(10);
        Pig pig=new Pig(10);
        //创建两个Thread对象
        Thread t1=new Thread(mon);
        Thread t2=new Thread(pig);
        //启动线程
        t1.start();
        t2.start();
    }
}
//输出
class Pig implements Runnable {
    int n;
    int times = 0;
    int sum = 0;

    public Pig(int n) {
        this.n = n;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我是一个线程,正在输出第" + times + "个Hello word");
            times++;
            if (times == n) {
                break;
            }
        }
    }
}
//计算
class Monkey implements Runnable {
    int n;
    int times = 0;
    int sum = 0;

    public Monkey(int n) {
        this.n = n;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            sum += (++times);
            System.out.println("当前值为:" + sum);
            if (times == n) {
                //System.out.println("最终值为:" + sum);
                break;
            }
        }
    }
}

2、线程对象只能启动一个线程
java线程的同步问题:多线程并发有很多好处,完成更有效的程序,但是也有很多安全问题,如下例子:

/*
功能:模拟机票售票系统,三个售票点在一天内卖出2000张票,
注意是一共卖出2000张,而不是每个卖出2000张
日期:2018/7/22
问题:出票线程是连续的
 */
public class Demo8 {
    public static void main(String []args){
        //创建一个窗口
        TicketWindows tw=new TicketWindows();
        //三个线程同时启动
        Thread t1=new Thread(tw);
        Thread t2=new Thread(tw);
        Thread t3=new Thread(tw);
        t1.start();
        t2.start();
        t3.start();
    }
}

//售票窗口类
class TicketWindows implements Runnable{
    private int ticket=2000;
    @Override
    public void run() {
            while (true) {
                //先判断是否还有票
                if (ticket > 0) {
                    //显示售票信息,Thread.currentThread().getName()获取线程名字
                    System.out.println(Thread.currentThread().getName() + "正在售票第" + ticket + " 张");
                    try {
                        //每秒售出一张
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket--;
                } else {
                    //售票结束
                    break;
                }
        }
    }
}

这里写图片描述
问题:出现同一张票被三个售卖点同时售卖
解决问题的关键:保证容易出问题的代码的原子性原子性是指当a线程在执行某代码时,别的线程必须等待其执行完后,才能执行它的代码;只需在需要同步的代码段用synchronized(Object){你要同步的代码},因此在上述代码修改如下:

while(true){
	//if else要保证其原子性[同步代码块]
	synchronized(this){
		if(){
		}
	}
}

这里写图片描述
保证了每张票只有一个售卖点在售出
同步机制
1)Java任意对象都有一个标志,该标志具有0、1两种状态,开始状态为1,当某个线程执行synchronized时,对象标志位为0,直到执行完个块代码块后,该标志位又回到1的状态。
2)当一个线程执行到synchronized语句时,先判断标志位,如果为0,则这个线程将暂时阻塞,让出cpu资源,直到另外的线程完成相关同步代码,并将Object标志为1,这个线程的阻塞暂时被取消,线程才继续运行,并将该线程的标志位变为0,防止其他代码块进入相关同步代码。
3)如果有多个线程因同时等待同一个对象的标志位而处于阻塞状态时,当该对象的标志位恢复到1时,只能有一个线程能够进入同步代码执行。
对象的标志位就是对象锁

原文地址:https://www.cnblogs.com/xq-mys/p/9350185.html