黑马程序员-----多进程

本文详细解析了Java多线程的概念、进程与线程的区别、多线程的创建方法、线程安全问题及解决方案、同步机制、线程间的通信、线程停止与守护线程等核心知识点,旨在帮助开发者深入掌握Java多线程编程。

——- android培训java培训、期待与您交流! ———-

1、 进程、线程、多线程的区别:
1)进程:是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该循序是一个执行路径,或叫控制单元。
2)线程:是进程中的一个独立的控制单元,线程在控制着进程的执行。
3)多线程:一个进程中可以有多个执行路径。
注意:一个进程中至少要有一个线程。
JVM启动时启动了多条线程,至少有两个线程可以分析的出来:
1.执行main函数的线程,该线程的任务代码都定义在main函数中。
2.负责垃圾回收的线程。

2、 创建线程的两种方法:
第一种方法:继承Thread类。
步骤:1)定义类继承Thread类
2)复写Thread类中的run方法
3)直接创建Thread的子类对象创建线程
4)调用线程的start方法(作用:启动线程;调用run方法)

class MyThread extends Thread
{
    public void run()
    { 
        //要在线程中执行的代码
        for(int i=0;i<100;i++)
            System.out.println("MyThread:"+i);
    }
}

第二种方法:实现Runnable接口。
步骤:1)定义类实现Runnable接口
2)覆盖Runnable接口中的run方法
3)通过Thread类建立线程对象
4)将Runnable接口的子类对象作为实际参数传给Thread类的构造函数
5)调用Thread类的start方法开启线程并调用Runnable接口子类的run方法

class MyThread1 implements Runnable
{
    public void run()
    { 
        //要在线程中执行的代码
        for(int i=0;i<100;i++)
            System.out.println("MyThread:"+i);
    }
}

完整代码示例演示:

package com.shan;
/**需求:建立一个多线程
 * @param args
 */
public class Demo37 {
    public static void main(String[] args) 
    {
        System.out.println("启动主线程");
        //启动第一个线程
        Thread t1=new MyThread();
        System.out.println("启动第一个线程");
        t1.start();

        //启动第二个线程
        MyThread1  mt=new MyThread1();
        Thread  t2=new Thread(mt);
        System.out.println("启动第二个线程");
        t2.start();


    }

}
class MyThread extends Thread //创建线程的第一种方式
{
    public void run()
    { 
        //要在线程中执行的代码
        for(int i=0;i<100;i++)
            System.out.println("MyThread:"+i);
    }
}
class MyThread1 implements Runnable  //创建线程的第二种方式
{
    public void run()
    { 
        //要在线程中执行的代码
        for(int i=0;i<100;i++)
            System.out.println("MyThread1:"+i);
    }
}

3、 实现方式和继承方式有什么区别?(重点)
1) 实现方式好处在于避免了单继承的局限性,在定义线程时,建议使用实现方式
2) 线程代码存放的位置不一样
继承Thread类:线程代码存放在Thread子类的run方法中。
实现Runnable接口:线程代码存放在接口的子类的run方法中

4、 线程都有自己默认的名称。Thread-编号(该编号从0开始)
Static Thread currentThread():获取当前线程对象
getName():获取线程名称
设置线程名称:setName或者构造函数

5、线程安全问题产生的原因:
1.多个线程在操作共享的数据。
2.操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
解决方案:
1)同步代码块:(java对于多线程的安全问题提供了专业的解决方式,就是同步代码块)

格式:synchronized(对象)
     {需要被同步的代码;}

2) 同步函数:

格式:在函数上加上synchronized修饰符即可。

示例演示:模拟4个线程同时卖100张票

package com.shan;
/**
 * 需求:模拟4个线程同时卖100张票。
 * @author ling
 *
 */
public class Demo38 {

        public static void main(String[] args)
        {
            Ticket t=new Ticket();
            Thread t1 =new Thread(t);
            Thread t2=new Thread(t);
            Thread t3=new Thread(t);
            Thread t4=new Thread(t);

            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }


}
class Ticket implements  Runnable
{
    private int num =1000;
    Object obj=new Object();
    public void run()
    {
        while(true)
        {
            synchronized(obj)
            {
                if(num>0)
                {
                    System.out.println(Thread.currentThread().getName()+"...sale..."+num--);
                }
            }
        }
    }
}

6、 同步的前提:
1) 必须要有两个或两个以上的线程;
2) 必须保证同步中只有一个线程在运行;
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,较为消耗资源。

7、 同步有两种表现形式:
一种是同步代码块;一种是同步函数

8、 同步函数使用的锁是this静态的同步函数使用的锁是该方法所在类的字节码文件对象,即:类名.class

示例演示:储户,两个,每个都到银行存钱,每次存100,共存三次。

classBank{
 privateintsum;
 publicsynchronizedvoidadd(intnum){//同步函数
 sum=sum+num;
 System.out.println("sum="+sum);
 }
 }
classCusimplementsRunnable{
privateBankb=newBank();
 publicvoidrun(){
 for(intx=0;x<3;x++){
 b.add(100);
 }
 }
 }

 classBankDemo{
 publicstaticvoidmain(String[]args){
 Cusc=newCus();
 Threadt1=newThread(c);
 Threadt2=newThread(c);
 t1.start();
 t2.start();
 }
 }

单例模式中的懒汉式就用到了同步函数

class Single{
 private static Single s = null;
 private Single(){}
 public static Single getInstance(){
 if(s ==null){
 synchronized(Single.class){
 if(s == null)
 s = new Single();
 }
 }
 return s ;
 }
 }

9、 死锁:同步中嵌套同步,就出现死锁现象。

10、线程间的通信:(等待唤醒机制)
1)操作线程的方法有:wait()/notify()/notifyAll();
为什么这些操作线程的方法要定义在Object类中呢?
分析:因为这些方法在操作同步中的线程时,都必须要标识它们所操作线程特有的锁,只有同一个锁上的被等待线程可以被同一个锁上的notify唤醒,不可以对不同锁中的线程唤醒。也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。
2) wait()和sleep()有什么区别?
分析:wait():释放资源释放锁,没有执行权。
sleep():释放资源不释放锁,有执行权。

示例演示:生产者—消费者

class Resource{
 private String name ;
 private String sex ;
 private boolean flag = false;

 public synchronized void set(String name,String sex){
 if(flag )
 try{
 this.wait();
 } catch(InterruptedException e){
 e.printStackTrace();
 }
 this.name = name;
 this.sex = sex;
 flag = true ;
 this.notify();
 }

 public synchronized void out(){
 if(!flag )
 try{
 this.wait();
 } catch(InterruptedException e){
 e.printStackTrace();
 }
 System. out.println(name + "..." + sex);
 flag = false ;
 this.notify();
}
 } 
class Input implements Runnable{
 Resource r;
 Input(Resource r){
 this.r = r;
 }

 public void run(){
 int x = 0;
 while(true ){
 if(x == 0){
 r.set( "mike","男" );
 } else{
 r.set( "lili","女" );
 }
 x = (x + 1)%2;
 }
 }
 }

 //输出
 class Output implements Runnable{
 Resource r;

 Output(Resource r){
 this.r = r;
 }

 public void run(){
 while(true ){
 r.out();
 }
 }
 }

 class ResourceDemo {
 public static void main(String[] args){
 //创建资源
 Resource r = new Resource();
 //创建任务
 Input in = new Input(r);
 Output out = new Output(r);
 //创建线程,执行路径
 Thread t1 = new Thread(in);
 Thread t2 = new Thread(out);
 //开启线程
 t1.start();
 t2.start();
}
}

11、 停止线程
1) 定义循环结束标记。
因为线程运行代码一般都是循环,只要控制了循环即可。
2) 使用interrupt(中断)方法
该方法是结束线程的冻结状态,是线程回到运行状态中来。
总结:如何停止线程?
只有一种,run方法结束。 开启多线程运行,运行代码通常是循环结构。 只要控制住循环,就可以让run方法结束,也就是线程结束。

12、 守护线程
setDaemon()方法是将该线程标记为守护线程或用户线程(后台线程)。当正在运行的线程都是守护线程时,java虚拟机自动退出。
该方法必须在启动线程前调用。
判断是否是后台线程:使用Thread对象的isDaemon()方法;
例如:

StopThread  st=new  StopThread  ();
Thread  t1=new Thread  (st);
Thread  t2=new Thread  (st);
t1.setDaemon(true);      //如果为true,则表示将该线程标记为守护线程
t2.setDaemon(true);
t1.start();
t2.start();

13、 join方法:
调用join方法的线程对象强制运行,该线程强制运行期间,其他线程无法运行,必须等到该线程结束后其他线程才可以运行。

join方法的重载方法:
join(long millis):
join(long millis,int nanos):

14、 线程的优先级:
每个线程都有优先级,优先级的高低只和线程获得执行机会的次数多少有关。
并非线程优先级越高的就一定先执行,哪个线程的先运行取决于CPU的调度;
默认情况下main线程具有普通的优先级,而它创建的线程也具有普通优先级。

Thread对象的setPriority(int x)getPriority()来设置和获得优先级。
MAX_PRIORITY    :   值是10
MIN_PRIORITY    :   值是1
NORM_PRIORITY   :   值是5(主方法默认优先级)

15、 线程让步:(yield)
暂停当前正在执行的线程对象,把执行机会让给相同或更高优先级的其他线程,让线程可以你一个我一个的进行交替执行。
——- android培训java培训、期待与您交流! ———-

内容概要:本文系统介绍了算术优化算法(AOA)的基本原理、核心思想及Python实现方法,并通过图像分割的实际案例展示了其应用价值。AOA是一种基于种群的元启发式算法,其核心思想来源于四则运算,利用乘除运算进行全局勘探,加减运算进行局部开发,通过数学优化器加速函数(MOA)和数学优化概率(MOP)动态控制搜索过程,在全局探索与局部开发之间实现平衡。文章详细解析了算法的初始化、勘探与开发阶段的更新策略,并提供了完整的Python代码实现,结合Rastrigin函数进行测试验证。进一步地,以Flask框架搭建前后端分离系统,将AOA应用于图像分割任务,展示了其在实际工程中的可行性与高效性。最后,通过收敛速度、寻优精度等指标评估算法性能,并提出自适应参数调整、模型优化和并行计算等改进策略。; 适合人群:具备一定Python编程基础和优化算法基础知识的高校学生、科研人员及工程技术人员,尤其适合从事人工智能、图像处理、智能优化等领域的从业者;; 使用场景及目标:①理解元启发式算法的设计思想与实现机制;②掌握AOA在函数优化、图像分割等实际问题中的建模与求解方法;③学习如何将优化算法集成到Web系统中实现工程化应用;④为算法性能评估与改进提供实践参考; 阅读建议:建议读者结合代码逐行调试,深入理解算法流程中MOA与MOP的作用机制,尝试在不同测试函数上运行算法以观察性能差异,并可进一步扩展图像分割模块,引入更复杂的预处理或后处理技术以提升分割效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值