Java学习笔记14

    技术2022-05-11  37

    ======================================================================   ======================================================================

    ======================================================================   java第十四天======================================================================

    (1) 线程的同步

    进程是一套顺序执行的指令。

    同时开辟并行执行序列即多线程          run() 结束,线程就结束

    JVM就是一个进程,在JVM中分出线程

    进程数据空间独立;线程数据空间共享, 线程间通信更容易

    分配的方式不如线程好,能充分使用CPU的资源。 共享数据就要加锁、解锁,会降低效率。

     

    OS 时分共享操作系统 实时操作系统

    时分共享操作系统    时间片    调度系统把每个时间片分给多个进程   性能调优是根据时间片划分, 时间片会影响整个操作系统。

     

    为了让某些工作并行,在进程主线程中开辟多个线程,这就是线程的机制。

     

     

    我们关心的是被线程共享的数据,主要看synchronized加在何处。往往不加在线程里面,而是在共享的对象上。

     

    只有运行状态的线程才有机会执行代码!

    只有等到所有线程终止,进程才结束!

    当一个对象分配给某线程锁标记时,其它线程不能访问同步方法,但能访问非同步方法!

     

    起线程的两种方式:1、继承Thread,覆盖run()方法,用start()启动

                      2、实现Runnable接口,用来构造线程对象。(线程对象不是线程,但代表一个线程)

    当多线程并发访问同一个对象(临界资源)的时候,如果原子操作被打破,则会造成数据的不一致.       java,用给临界资源加锁的机制来解决这个问题.       每一个对象都有一个互斥锁标记(monitor),只能分配给一个线程(对象相当于女孩,每个女孩都有一个锁标记,并且这个锁标记只能给一个男孩(线程)).       synchronized(o[对象的引用]){O对象加锁的同步代码块}       synchronized可以作为一个方法的修饰符,对当前对象加锁.       例子:       public synchronized void m(){}       public void m(){           synchronized(this){}//对当前对象的方法加锁.       }       每一个对象都有一个锁池,它里面装的是等待该对象锁标记的线程.(就象每个女孩都有一个锁池,里面放着等待要这个女孩锁标记的男孩(线程))       一个线程可以拥有多个对象的标记.同步代码块是可以嵌套的(一个男孩可以有多个女孩的锁标记,但是一个女孩只能有一个男朋友)换句话说就是(一个线程可以拿到多个对象的锁标记,但是一个对象的锁标记只能给一个线程。).       synchronized(o1){            synchronized(o2){ //一个线程可以拥有多个对象的锁标记.               t1;           }       }       当一个对象拥有一个对象的锁标记的时候,在另一个对象的锁池等待的时候不会释放拥有的锁(一个男孩在拥有了一个女孩的锁标记的时候,还在等待另一个女孩的锁标记,在等待的时候不会释放上一个女孩的锁标记。).       当一个拥有一个对象的锁标记的线程访问这个对象的时候,其他的对象不能访问这个对象的同步方法,只能访问这个对象的非并发方法.(当一个女孩发出锁标记的时候,就是有了男朋友,这个对象就被加了锁,她定义的同步方法(拥抱,接吻,#%&%$#)只能这个男朋友访问,其他男孩不能访问,其他的男孩只能访问这个女孩的非加锁方法)呵呵.       当一个线程阻塞在一个对象的锁池里的时候,不会释放其所拥有的其他对象的的锁标记       每一个线程不释放自己拥有的资源,却申请别的线程,会造成死锁。

    -------------------------------------------------------------------------------   (3) 解决死锁问题 进程间通信   (4) 每个对象有一个等待队列的空间.   (5) 等待机制:       调用wait()方法的条件,必需在这个同步代码块中.       当调用wait()方法的时候       线程t1: o.wait();           前提: 必需在对o加锁的同步代码块里.           结果:                1: t1会释放器所拥有的所有的锁标记.               2: t1会进入o的等待队列.   (6) 通知机制       线程t2:  o.notify()/o.notifyAll(); [线程执行这个代码,全当是发善心,因为他可以把其他线程从井里面救出来,也可以不救出来]           前提: 必需在对o加锁的同步代码块里.           结果: 1: t2会从o的等待队列中释放一个线程/所有线程.

    wait() sleep()的联系和区别:

    1. wait()是从Object继承下来的方法,而sleep()Thread中的静态方法

    2. wait() sleep()都要阻塞运行,释放CPU资源

    3. wait()要释放锁; 而sleep()不释放锁

    wait()方法被调用时会解除锁定,但是我们能使用它的地方只是在一个同步方法或代码块内。

       锁池: 是被迫进入,   等待队列: 是一个(),在进去的时候把所有的资源释放,怎么才能出去,别人把你救出去.别人调用notify()/notifyAll()   进程之间进行通信需要一个标记值来调度两个线程.   例子: (生产者和消费者的例子) public class TestPC {

        public static void main(String[] args) {

            MyStack stack=new MyStack();

            PushThread t1=new PushThread(stack);

            PushThread2 t3=new PushThread2(stack);

            PopThread t2=new PopThread(stack);   

            t1.start();//其中一个生产者.

            t3.start();//另一个生产者.

            t2.start();//消费者.

        }

    }   

    class MyStack{//临界资源,要加锁。

        char[] data=new char[6];

        int index;//需要全局属性来调度.

        public synchronized void push(char c){

            if(data.length==index){

                try {

                    this.wait();//释放自己所有的资源,包括自己拥有的锁.这样其他的线程就可以访问这个锁定的方法.

                } catch (InterruptedException e) {

                }

            }

            System.out.println(c+" pushed!!");

            data[index]=c;

            index++;//标记值加1.调度两个线程.

            this.notifyAll();//从等待队列中把等待操作这个对象的线程调出来,把它从等待状态变成锁池状态.

            this.print();//打印栈中的元素。

        }

        public synchronized void pop(){

            if(index==0){

                try {

                    this.wait();//释放自己所有的资源,包括自己拥有的锁.这样其他的线程就可以访问这个锁定的方法.

                } catch (InterruptedException e) {

                }

            }

            index--;//标记值减1;

            System.out.println(data[index]+" poped!!");

            data[index]=' ';           

            this.notifyAll();

            this.print();

        }

        public void print(){

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

                System.out.print(data[i]+" ");   

            }

            System.out.println();

        }

    }   

    class PushThread extends Thread{//操作这个栈的一个线程(入栈)。

        MyStack stack;

       

        public PushThread(MyStack stack) {

            this.stack = stack;

        }

     

        public void run(){

            for(char i='A';i<'Z';i++){

                stack.push(i);//调用入栈方法.

                System.out.println("PushThread1 ");

            }

           

        }

    }   

    class PopThread extends Thread{//操作这个栈的另一个线程(出栈)。

        MyStack stack;   

        public PopThread(MyStack stack) {

            this.stack = stack;

        }   

        public void run(){

            for(char i='A';i<'Z';i++){

                stack.pop();//调用出栈方法.

            }

        }

    }   

    class PushThread2 extends Thread{

        MyStack stack;

     

        public PushThread2(MyStack stack) {

            this.stack = stack;

        }

        public void run(){

            for(char i='A';i<'Z';i++){

                stack.push(i);

                System.out.println("PushThread2");

            }           

        }       

    }

     

    ----------------------------------------------------------------------------   作业:

    新思路:必要时可利用Object中的 锁标记锁池等待队列 用其wait() / notify() 方法,

           自己制造临界资源来进行线程间通讯。

          (参考字母数字交叉打印的例子TestNumberCharPrint.java

           其中注意o.notifyAll() o.wait() 的调用顺序,还要注意边界问题,体现在最后要来一个判断if(c!=’Z’)  o.wait(); 进而让程序正常结束。

     public class HomeWork {

        public static void main(String[] args) {

            Run r = new Run();

            Thread1 t1 = new Thread1(r);

            Thread2 t2 = new Thread2(r);

            t1.start();

            t2.start();

        }

    }

    class Run {

        int index = 1;

        public synchronized void printNum() {

            for (int i = 1; i <= 52; i++) {

                while (index % 3 == 0) {

                    try {

                        this.wait();

                    } catch (InterruptedException e) {

                    }

                }

                System.out.print(i + " ");

                index++;

                this.notifyAll();

            }

        }

        public synchronized void printChar() {

     

            for (char j = 'A'; j < 'Z'; j++) {

                while (index % 3 != 0) {

                    try {

                        this.wait();

                    } catch (InterruptedException e) {

                    }

                }

                index++;

                System.out.print(j + " ");

                this.notifyAll();

            }

        }

    }

    class Thread1 extends Thread {

        Run r;

     

        public Thread1(Run r) {

            this.r = r;

        }

        public void run() {

            r.printNum();

        }

    }

    class Thread2 extends Thread {

        Run r;

        public Thread2(Run r) {

            this.r = r;

        }

        public void run() {

            r.printChar();

        }

    }

     

     

    (1) 线程的同步

    进程是一套顺序执行的指令。

    同时开辟并行执行序列即多线程          run() 结束,线程就结束

    JVM就是一个进程,在JVM中分出线程

    进程数据空间独立;线程数据空间共享, 线程间通信更容易

    分配的方式不如线程好,能充分使用CPU的资源。 共享数据就要加锁、解锁,会降低效率。

     

    OS 时分共享操作系统 实时操作系统

    时分共享操作系统    时间片    调度系统把每个时间片分给多个进程   性能调优是根据时间片划分, 时间片会影响整个操作系统。

     

    为了让某些工作并行,在进程主线程中开辟多个线程,这就是线程的机制。

     

     

    我们关心的是被线程共享的数据,主要看synchronized加在何处。往往不加在线程里面,而是在共享的对象上。

     

    只有运行状态的线程才有机会执行代码!

    只有等到所有线程终止,进程才结束!

    当一个对象分配给某线程锁标记时,其它线程不能访问同步方法,但能访问非同步方法!

     

    起线程的两种方式:1、继承Thread,覆盖run()方法,用start()启动

                      2、实现Runnable接口,用来构造线程对象。(线程对象不是线程,但代表一个线程)

    当多线程并发访问同一个对象(临界资源)的时候,如果原子操作被打破,则会造成数据的不一致.       java,用给临界资源加锁的机制来解决这个问题.       每一个对象都有一个互斥锁标记(monitor),只能分配给一个线程(对象相当于女孩,每个女孩都有一个锁标记,并且这个锁标记只能给一个男孩(线程)).       synchronized(o[对象的引用]){O对象加锁的同步代码块}       synchronized可以作为一个方法的修饰符,对当前对象加锁.       例子:       public synchronized void m(){}       public void m(){           synchronized(this){}//对当前对象的方法加锁.       }       每一个对象都有一个锁池,它里面装的是等待该对象锁标记的线程.(就象每个女孩都有一个锁池,里面放着等待要这个女孩锁标记的男孩(线程))       一个线程可以拥有多个对象的标记.同步代码块是可以嵌套的(一个男孩可以有多个女孩的锁标记,但是一个女孩只能有一个男朋友)换句话说就是(一个线程可以拿到多个对象的锁标记,但是一个对象的锁标记只能给一个线程。).       synchronized(o1){            synchronized(o2){ //一个线程可以拥有多个对象的锁标记.               t1;           }       }       当一个对象拥有一个对象的锁标记的时候,在另一个对象的锁池等待的时候不会释放拥有的锁(一个男孩在拥有了一个女孩的锁标记的时候,还在等待另一个女孩的锁标记,在等待的时候不会释放上一个女孩的锁标记。).       当一个拥有一个对象的锁标记的线程访问这个对象的时候,其他的对象不能访问这个对象的同步方法,只能访问这个对象的非并发方法.(当一个女孩发出锁标记的时候,就是有了男朋友,这个对象就被加了锁,她定义的同步方法(拥抱,接吻,#%&%$#)只能这个男朋友访问,其他男孩不能访问,其他的男孩只能访问这个女孩的非加锁方法)呵呵.       当一个线程阻塞在一个对象的锁池里的时候,不会释放其所拥有的其他对象的的锁标记       每一个线程不释放自己拥有的资源,却申请别的线程,会造成死锁。

    -------------------------------------------------------------------------------   (3) 解决死锁问题 进程间通信   (4) 每个对象有一个等待队列的空间.   (5) 等待机制:       调用wait()方法的条件,必需在这个同步代码块中.       当调用wait()方法的时候       线程t1: o.wait();           前提: 必需在对o加锁的同步代码块里.           结果:                1: t1会释放器所拥有的所有的锁标记.               2: t1会进入o的等待队列.   (6) 通知机制       线程t2:  o.notify()/o.notifyAll(); [线程执行这个代码,全当是发善心,因为他可以把其他线程从井里面救出来,也可以不救出来]           前提: 必需在对o加锁的同步代码块里.           结果: 1: t2会从o的等待队列中释放一个线程/所有线程.

    wait() sleep()的联系和区别:

    1. wait()是从Object继承下来的方法,而sleep()Thread中的静态方法

    2. wait() sleep()都要阻塞运行,释放CPU资源

    3. wait()要释放锁; 而sleep()不释放锁

    wait()方法被调用时会解除锁定,但是我们能使用它的地方只是在一个同步方法或代码块内。

       锁池: 是被迫进入,   等待队列: 是一个(),在进去的时候把所有的资源释放,怎么才能出去,别人把你救出去.别人调用notify()/notifyAll()   进程之间进行通信需要一个标记值来调度两个线程.   例子: (生产者和消费者的例子) public class TestPC {

        public static void main(String[] args) {

            MyStack stack=new MyStack();

            PushThread t1=new PushThread(stack);

            PushThread2 t3=new PushThread2(stack);

            PopThread t2=new PopThread(stack);   

            t1.start();//其中一个生产者.

            t3.start();//另一个生产者.

            t2.start();//消费者.

        }

    }   

    class MyStack{//临界资源,要加锁。

        char[] data=new char[6];

        int index;//需要全局属性来调度.

        public synchronized void push(char c){

            if(data.length==index){

                try {

                    this.wait();//释放自己所有的资源,包括自己拥有的锁.这样其他的线程就可以访问这个锁定的方法.

                } catch (InterruptedException e) {

                }

            }

            System.out.println(c+" pushed!!");

            data[index]=c;

            index++;//标记值加1.调度两个线程.

            this.notifyAll();//从等待队列中把等待操作这个对象的线程调出来,把它从等待状态变成锁池状态.

            this.print();//打印栈中的元素。

        }

        public synchronized void pop(){

            if(index==0){

                try {

                    this.wait();//释放自己所有的资源,包括自己拥有的锁.这样其他的线程就可以访问这个锁定的方法.

                } catch (InterruptedException e) {

                }

            }

            index--;//标记值减1;

            System.out.println(data[index]+" poped!!");

            data[index]=' ';           

            this.notifyAll();

            this.print();

        }

        public void print(){

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

                System.out.print(data[i]+" ");   

            }

            System.out.println();

        }

    }   

    class PushThread extends Thread{//操作这个栈的一个线程(入栈)。

        MyStack stack;

       

        public PushThread(MyStack stack) {

            this.stack = stack;

        }

     

        public void run(){

            for(char i='A';i<'Z';i++){

                stack.push(i);//调用入栈方法.

                System.out.println("PushThread1 ");

            }

           

        }

    }   

    class PopThread extends Thread{//操作这个栈的另一个线程(出栈)。

        MyStack stack;   

        public PopThread(MyStack stack) {

            this.stack = stack;

        }   

        public void run(){

            for(char i='A';i<'Z';i++){

                stack.pop();//调用出栈方法.

            }

        }

    }   

    class PushThread2 extends Thread{

        MyStack stack;

     

        public PushThread2(MyStack stack) {

            this.stack = stack;

        }

        public void run(){

            for(char i='A';i<'Z';i++){

                stack.push(i);

                System.out.println("PushThread2");

            }           

        }       

    }

     

    ----------------------------------------------------------------------------   作业:

    新思路:必要时可利用Object中的 锁标记锁池等待队列 用其wait() / notify() 方法,

           自己制造临界资源来进行线程间通讯。

          (参考字母数字交叉打印的例子TestNumberCharPrint.java

           其中注意o.notifyAll() o.wait() 的调用顺序,还要注意边界问题,体现在最后要来一个判断if(c!=’Z’)  o.wait(); 进而让程序正常结束。

     public class HomeWork {

        public static void main(String[] args) {

            Run r = new Run();

            Thread1 t1 = new Thread1(r);

            Thread2 t2 = new Thread2(r);

            t1.start();

            t2.start();

        }

    }

    class Run {

        int index = 1;

        public synchronized void printNum() {

            for (int i = 1; i <= 52; i++) {

                while (index % 3 == 0) {

                    try {

                        this.wait();

                    } catch (InterruptedException e) {

                    }

                }

                System.out.print(i + " ");

                index++;

                this.notifyAll();

            }

        }

        public synchronized void printChar() {

     

            for (char j = 'A'; j < 'Z'; j++) {

                while (index % 3 != 0) {

                    try {

                        this.wait();

                    } catch (InterruptedException e) {

                    }

                }

                index++;

                System.out.print(j + " ");

                this.notifyAll();

            }

        }

    }

    class Thread1 extends Thread {

        Run r;

     

        public Thread1(Run r) {

            this.r = r;

        }

        public void run() {

            r.printNum();

        }

    }

    class Thread2 extends Thread {

        Run r;

        public Thread2(Run r) {

            this.r = r;

        }

        public void run() {

            r.printChar();

        }

    }

     

     

    最新回复(0)