java线程创建篇

进程和线程:
进程是指一个内存中运行中的应用程序,每个进程都有自己独立的一块内存空间。
一个进程至少一个线程,为了提高效率,一个进程中开启多个执行任务,即多线程。
开启新的进程很耗费内存和性能。
进程和线程的区别:
进程:有独立的内存空间,进程中的数据存放空间(堆空间和栈空间)是独立的,至少有一个线程。
线程:堆空间是共享的,栈空间是独立的,线程消耗的资源比进程小,相互可以影响。
从微观角度线程也有先后。

Java程序的进程(java的一个程序运行在系统中)至少包含主线程和垃圾回收线程。

线程调度:
计算机通常只有一个cpu,在任意时刻只能执行一条计算机指令,每一个进程只有获得cpu的使用权才能执行指令。从宏观上讲,就是各个进程轮流获得cpu使用权,分别执行各自的任务。
Jvm采用抢占式调度,没有采用分时调度,因此可能造成多线程执行结果的随机性。
多线程的优势:
进程之间不能共享内存,线程之间共享内存(堆内存)
系统创建进程时需要为该进程重新分配系统资源,因此多任务并发时,多线程的效率更高。
Java语言本身内置多线程功能的支持,而不是单纯作为底层系统的调度方式,从而简化了多线程编程。
CPU线程数也影响了系统的速率,买电脑可以看看。

宽带带宽以单位(bit)计算,而下载速度是以字节(Byte)为单位,一个字节等于8个bit。所以你是1M带宽,那要先除以8,而且要低一点。
多线程抢占资源更快,更多。
Java操作进程
在java代码中如何运行一个进程(简单讲解,获取继承中的数据)

**Runtime类中的exec方法
ProcessBuilder的start方法**

import java.io.IOException;

public class Demo5 {
    public static void main(String[] args) throws IOException {
        //是同Runtime类的exec方法

        Runtime runtime = Runtime.getRuntime();
        runtime.exec("notepad");

        //方式二:ProcessBuilder的start()方法

        ProcessBuilder pb = new ProcessBuilder("notepad");
        pb.start();
    }
}

创建和启动线程,传统有两种方式:
继承手段:
实现接口的手段:
线程类(java.Lang.Thread)Thread类和Thread子类才能称之为线程类
别忘了主线程main

方式1:继承Thread类

定义一个类A继承于java.lang.Thread类
在类A中覆盖Thread类中的run方法
我们在run方法中填写需要执行的操作—run方法里的线程执行体
在main方法(线程)中,创建线程对象并启动线程
创建线程类 A类 th = new A类();
调用线程对象的start方法: th.start();
注意:千万不要调用run方法,如果调用润方法好比对象调用方法,依然还是只有一个线程,并没有启动新的线程

例子:边唱歌边玩游戏

//播放音乐的线程类
class MusicThread extends java.lang.Thread{

    public void run() {
        for(int i = 0; i < 50 ; i ++) {
            System.out.println("播放音乐.."+ i);
        }
    }
}

public class Demo6 {
    public static void main(String[] args) {
        //主线程:运行游戏
        for(int i = 0; i < 50 ; i ++ ) {
            System.out.println("打游戏.." + i);
            if(i == 10) {
                //创建线程对象,并启动线程
                MusicThread t = new MusicThread();
                t.start();
            }
        }
    }
}

结果有不可预知性,线程只能启动一次
实现接口Runnable接口
定义一个类A实现一个接口叫做Runnable接口
在A类中覆盖Runnable接口中的run方法
我们在run方法中编写并执行操作—run方法中的线程执行体
在main方法(线程)中,创建线程对象,并启动线程
创建线程类对象 Thread t = new Thread();
调用线程对象的start方法 t.start();

//播放音乐的一个类
class music implements java.lang.Runnable{
    public void run() {
        for(int i = 0; i < 50 ; i ++) {
            System.out.println("播放音乐.."+ i);
        }
    }
}

public class Demo7 {
    public static void main(String[]  args) {
        //主线程:运行游戏
                for(int i = 0; i < 50 ; i ++ ) {
                    System.out.println("打游戏.." + i);
                    if(i == 10) {
                        //创建线程对象,并启动线程
                        music tar = new music();
                        Thread t = new Thread(tar);
                        t.start();
                    }
                }
    }
}

**使用匿名内部类创建线程
匿名内部类
只适用于使用一次的情**况

public class Demo8 {
    public static void main(String[] args) {
        //主线程,运行游戏
        for(int i = 0; i < 50; i++) {
            System.out.println("打游戏.."+ i);
            if(i == 10) {
                //创建线程对象,并启动线程
                new Thread(new Runnable() {
                    public void run() {
                        for(int i = 0; i < 50; i++) {
                            System.out.println("打豆豆.."+ i);
                        }
                    }
                }).start();
            }
        }
    }
}

吃苹果案例
有五十个苹果,让三个人吃完苹果,三个同学代号a,b,c,此时要使用多线程技术来实现这个案例,a,b,c可以同时吃苹果,看谁吃的快?

分析:可以定义三个线程对象,并启动线程。
每一个同学吃苹果的时候,先显示自己拿到手上苹果的编号,在吃掉苹果,意味着苹果总数少一个。

**方式1:使用Thread类方式实现
方式2:使用Runnable接口实现**


方式1:-//用继承方式实现让3个同学吃50苹果的方法
class Person extends Thread {
    private int num = 50;

    public Person(String name) {
        super(name);
    }
    public void run() {
        for(int i = 0; i < 50; i++) {
            if(num > 0 ) {
                System.out.println(super.getName()+"编号为"+num--+"被吃");
            }
        }
    }
}

public class Demo9 {
    public static void main(String[] args) {
        //创建三个线程:三个同学吃苹果
        new Person("a").start();; 
        new Person("b").start();; 
        new Person("c").start();; 
    }
}

这时候三个每个吃50,各自拥有一个num=50这是不可行的

方式2//使用实现接口方式来实现三人吃苹果比赛

class Person implements Runnable {
    private int num = 50;

    //static Thread currentThread()
    //返回当前线程的引用
    public void run() {
        for(int i = 0; i < 50; i++) {
            if(num > 0 ) {
                System.out.println(Thread.currentThread().getName()+"编号为"+num--+"被吃");
            }
        }
    }
}
public class Demo10 {
    public static void main(String[] args) {
        Person a = new Person();
        new Thread(a,"a").start();
        new Thread(a,"b").start();
        new Thread(a,"c").start();
    }

}

在使用接口时,三个人一共吃了50个苹果,因为三个线程共享了一个对象Person,而一个Person中只有50苹果

**分析继承方式和实现方式的优缺点
继承方式:1)面向对象:java中类是单继承的,如果继承了Thread类,该类就不能再有其他的父类了
2)从操作上说继承方式更简单,获取线程名字也简单
3)不能实现共享资源,除非加static
实现方式:1)面向对象:java中类可以多实现接口,此时该类可以继承其他类,并且还可以实现其他接口
2)从操作上说实现方式复杂点,名字获取需要Thread.currentThread()来获取当前线程的引用
3)可以做到共享资源
同步代码块:**
语法synchronlzed(同步锁){
需要同步操作的代码
}
同步锁:为了保证每个线程都能正常执行原子操作,java引入了线程同步机制
同步监听对象/同步锁/同步监听器/互斥锁
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁
Java程序运行使用任何对象作为同步监听对象,但是一般我们把当前发生并发访问的共同资源作为同步监听对象。
在任何时候最多允许一个线程拥有同步锁,谁拿到就进去,其他人等着。

//用继承方式实现让3个同学吃50苹果的方法
class Person1 implements Runnable {
    private static int num = 50;

    public void run() {

        //同步代码块
        for(int i = 0; i < 50; i++) {

            synchronized (this) {
            if(num > 0 )    {
                System.out.println(Thread.currentThread().getName()+"编号为"+num+"被吃");
                }
            //模拟网络延迟
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
                num--;
            }
        }
    }
}

public class Demo11 {
    public static void main(String[] args) {
        //创建三个线程:三个同学吃苹果
        Person1 shh = new Person1();
        new Thread(shh,"aa").start();; 
        new Thread(shh,"bb").start();; 
        new Thread(shh,"cc").start();; 
    }
}

同步方法:
使用synchronized修饰的方法就是同步方法,保证了a调用这个方法,其他等着,a结束,其他人才有机会
Synchronized public void dowork() {

}
此时同步锁是谁?????对于非static方法,同步锁就是this
对于static方法,我们使用当前方法所在类的字节码对象。(Apple.class)

//用继承方式实现让3个同学吃50苹果的方法
class Person4 implements Runnable {
    private static int num = 50;

    synchronized public void run() {

        //同步代码块
        for(int i = 0; i < 50; i++) {


            if(num > 0 )    {
                System.out.println(Thread.currentThread().getName()+"编号为"+num+"被吃");
                }
            //模拟网络延迟
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
                num--;
            }
        }

}

public class Demo12 {
    public static void main(String[] args) {
        //创建三个线程:三个同学吃苹果
        Person4 shh = new Person4();
        new Thread(shh,"aa").start();; 
        new Thread(shh,"bb").start();; 
        new Thread(shh,"cc").start();; 
    }
}

被一个人吃完了,synchronized不可以修饰run方法,修饰之后,某一个线程就执行完了所有任务,达不到多线程的效果
解决方法:吧需要同步操作的代码定义在新的方法中并用synchronized修饰,run中调用

//用继承方式实现让3个同学吃50苹果的方法
class Person4 implements Runnable {
    private static int num = 50;

    public void run() {

        //同步代码块
        for(int i = 0; i < 50; i++) {

        test(); 

        }
    }
    synchronized private void test() {
            if(num > 0 )    {
                System.out.println(Thread.currentThread().getName()+"编号为"+num+"被吃");

                //模拟网络延迟
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                }
                    num--;
                }
    }
}



public class Demo12 {
    public static void main(String[] args) {
        //创建三个线程:三个同学吃苹果
        Person4 shh = new Person4();
        new Thread(shh,"aa").start();; 
        new Thread(shh,"bb").start();; 
        new Thread(shh,"cc").start();; 
    }
}

Synchronized的好与坏
好处:保证了多线程并发访问时的同步操作避免了线程的安全性问题

坏处:使用这个的性能比不用要低

尽量减小synchronized的作用域
StringBuilder和StringBuffer区别:
StringBuffer都加了synchronized
说说ArrayList和Vector的区别或者HashMap和Hashtable的区别
也是synchronized的区别

猜你喜欢

转载自blog.csdn.net/qq_42784105/article/details/81566663