javase笔记day23

多线程

线程是依赖于进程存在的
进程就是正在运行的程序,是系统进行资源分配和调用的独立单位。
每一个进程都有它自己的内存空间和系统资源。
一个进程可以启动多个线程

比如java程序:
	JVM就是一个进程,main为主线程,垃圾回收也是一个线程,两个线程并发	
	
线程:在一个进程内部又可以执行多个任务,而这每一个任务我们就可以看成是一个线程。是程序使用CPU的基本单位。所以,进程是拥有资源的基本单位, 线程是CPU调度的基本单位。

多线程的作用不是提高执行速度,而是为了提高应用程序的使用率
程序在运行的使用,都是在抢CPU的时间片(执行权),如果是多线程的程序,那么在抢到
CPU的执行权的概率应该比较单线程程序抢到的概率要大,CPU在多线程程序中执行的时间要比单线程多,所以就提高了程序的使用率.但是即使是多线程程序,那么他们中的哪个线程能抢占到CPU的资源呢,这个是不确定的,所以多线程具有随机性.

并发:
	指应用能够交替执行不同的任务
并行:
	指应用能够同时执行不同的任务
	
	进程并行,线程并发

实现多线程

方式一:
	创建一个类继承Thread类
	重写Thread类的run方法
	new出创建类,调用start方法开启线程
	
方式二:(扩展性强,实现接口,可以去继承其他类)
	创建一个类去实现Runnable接口
	重写Runnable接口的run方法
	分配创建类的实例
	再创建Thread对象,将实例传入Thread对象
	调用start方法开启线程
	
方式三:(这种方式有返回值,可以抛出异常)
	创建一个类实现 Callable 接口
	重写Callable接口中的call方法
	创建一个FutureTask类将Callable接口的子类对象作为参数传进去
	创建Thread类, 将FutureTask对象作为参数传进去
	调用start方法开启线程

举例

//方式一:
package org.javase.线程;

public class Test2 {
    public static void main(String[] args) {
        //创建线程对象
        MyThread1 myThread = new MyThread1();

        //开启线程
        myThread.start();

    }
}
class MyThread1 extends Thread{

    @Override
    public void run() {


    }
}

//方式二:
	package org.javase.线程;

public class Test2 {
    public static void main(String[] args) {
        //创建实例
        MyThread1 myThread = new MyThread1();

        //创建线程对象(传入实例)
        Thread thread = new Thread(myThread);

        //开启线程
        thread.start();

    }
}
class MyThread1 implements Runnable{

    @Override
    public void run() {
        
    }
}

//方式三:
	package org.javase.线程;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Test2 {
    public static void main(String[] args) {
        //创建实例(传入100)
        MyCallable mc = new MyCallable(100);

        //创建FutureTask对象(传入实例)
        FutureTask<Integer> ft = new FutureTask<Integer>(mc);

        //创建线程对象(对象参数)
        Thread thread = new Thread(ft);

        //开启线程
        thread.start();

    }
}
class MyCallable implements Callable<Integer> {

    private int num;

    public MyCallable(int num){
        this.num = num;
    }

    @Override
    public Integer call() throws Exception {
        //求1~100的和
        int sum = 0;
        for (int i = 0; i < num ; i++) {
            sum += i;
        }
        return sum;
    }
}

为什么要重写run方法?
	这个类是一个线程类,那么在这个类中我们可不可以写一些其他的方法呢?
	我们可以在写其他的方法,那么其他方法中封装的代码都是需要被我们线程执行的吗? 不一定
   那么也就是run方法中封装应该是必须被线程执行的代码.
   
 run方法中的代码的书写原则: 一般是比较耗时的代码

Thread类的方法

public final String getName()获取线程名称
public final void setName(String name)设置线程名称
public static Thread currentThread()获取当前执行的线程
public final int getPriority() //获取线程的优先级
public final void setPriority(int newPriority)//设置线程的优先级
public final int getPriority()返回线程的优先级,(线程的默认优先级是5)

线程休眠

//public static void sleep(long millis) 线程休眠
package org.westos.作业;

public class ThreadTest1 {
    public static void main(String[] args) throws InterruptedException {
        
        System.out.println("主线程开始执行了");
        Thread.sleep(2000);
        System.out.println("主线程下面的代码");
        //线程休眠:可以让当前正在执行的线程, 睡一会。
        //Thread(String name) 分配新的 Thread 对象。
        //通过有参构造,可以给线程起个名字
        MyThread1 th1 = new MyThread1("A线程");
        MyThread1 th2 = new MyThread1("B线程");

        th1.start();
        th2.start();

    }
}
class MyThread1 extends Thread{
    public MyThread1(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                //线程休眠
                Thread.sleep(1000); //单位是毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String name1 = Thread.currentThread().getName();
            System.out.println(name1 + "===" + i);
        }
    }
}

加入线程

package org.westos.作业;


public class MyThread extends Thread{
    public MyThread(){}
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i <20; i++) {
            String name1 = Thread.currentThread().getName();
            System.out.println(name1 + "===" + i);
        }
    }
}
class ThreadTest2{
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new MyThread();
        Thread t2 = new MyThread();
        Thread t3 = new MyThread();

        t1.setName("monkey sun");
        t2.setName("猪八戒");
        t3.setName("唐僧");

        //加入线程
        
       /* public final void join ()加入线程
        意思就是:等待该线程执行完毕了以后, 其他线程才能再次执行
        注意事项:
        在线程启动之后, 在调用方法
        join ()可以让多个线程并发执行,变成串行(挨个排队执行,不用抢)*/
        t1.start();
        t1.join();
        t2.start();
        t2.join();

        t3.start();
        t3.join();

    }
}

礼让线程

public static void yield()
	暂停当前正在执行的线程对象,并执行其他线程。 

	礼让是要暂停当前正在执行的线程,这个暂停的时间是相当短的,如果在这个线程暂停完毕以后,其他的线程还没有抢占到CPU的执行权,那么这个时候这个线程应该再次和其他线程抢占CPU的执行权. 

守护线程

用户线程和守护线程的区别
    用户线程和守护线程都是线程,区别是Java虚拟机在所有用户线程dead后,程序就会结束。而不管是否还有守护线程还在运行,若守护线程还在运行,则会马上结束。很好理解,守护线程是用来辅助用户线程的,如公司的保安和员工,各司其职,当员工都离开后,保安自然下班了。
    
    创建守护线程
    	调用线程对象的方法setDaemon(true),设置线程为守护线程。
            1)thread.setDaemon(true)必须在thread.start()之前设置。
            2)在Daemon线程中产生的新线程也是Daemon的。
            3)不是所有的应用都可以分配给Daemon线程来进行服务,比如读写操作或者计算逻辑。
    因为Daemon Thread还没来得及进行操作,虚拟机可能已经退出了。
package org.westos.作业;


public class ThreadTest3 {
    public static void main(String[] args) throws InterruptedException {
        Thread.currentThread().setName("主线程唐僧");
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"=="+i);
        }

        MyThread th1 = new MyThread();
        MyThread th2 = new MyThread();
        th1.setName("张飞");
        th2.setName("关羽");
        //设置为守护线程 当主线程死亡后,守护线程要立马死亡掉。
        //注意:setDaemon(true)该方法必须在启动线程前调用。
        th1.setDaemon(true);
        th2.setDaemon(true);
        th1.start();
        th2.start();

        System.out.println(Thread.currentThread().getName()+"退出了");
    }
}
class MyThread extends Thread{
    public MyThread(){}
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i <2000; i++) {
            String name1 = Thread.currentThread().getName();
            System.out.println(name1 + "===" + i);
        }
    }
}

中断线程

public final void stop():		停止线程的运行
public void interrupt():		中断线程,查看API可得当线程调用
wait(),sleep(long time)		方法的时候处于阻塞状态,可以通过这个方法清除阻塞

卖票

线程安全问题的产生原因:
	否是多线程环境
	是否有共享数据
	是否有多条语句操作共享数据
	
	解决线程安全:
		使用同步代码块:
 			格式: 	
 		synchronized(对象){
 			//不能在括号了直接new 对象 new 了 就没效果
			要被同步的代码 ;
		}
package org.westos.作业;

public class ThreadTest3 {
    public static void main(String[] args) {
        MyRunnable mr = new MyRunnable();

        Thread t1 = new Thread(mr,"窗口一");
        Thread t2 = new Thread(mr,"窗口二");
        Thread t3 = new Thread(mr,"窗口三");

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



    }
}
class MyRunnable implements Runnable{
    static int ticket = 100;
    static Object o = new Object();
    @Override
    public void run() {


            while (true) {
                //使用同步代码块锁住一个线程
                synchronized (o) {
                    if (ticket > 0) {

                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在卖出第" + (ticket--) + "票");
                    }
                }
            }

    }
}

给方法上进行同步

同步代码块:锁对象是任意一个对象
同步方法:锁对象用的是this当前对象
静态同步方法:锁对象使用是当前字节码文件
package org.westos.作业;

public class CellRunnable implements Runnable {
    //这个票让三个线程共享
    static int piao = 100; //共享数据
    //确保这个锁对象,只有一个,多个线程共用一把锁
    static Object obj = new Object();
    int i = 1;

    @Override
    public void run() {
        while (true) {
            // 假如就剩最后一张票  int piao=1;
            //th1 th2 th3
            if (i % 2 == 0) {
                synchronized (this) { //
                    //当th1这个线程进来同步代码块后,就持有了这个锁,其他线程没有持有锁,那么就要处于等待状态,等在同步代码块的外面
                    if (piao >= 1) {
                        //模拟一下真实的售票环境,有网络延迟。
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在出售第:" + (piao--) + " 张票");
                    }
                }
            } else {
                maiPiao();
            }

            i++;

            //th1 执行完了,出了同步代码块,就会释放锁。释放锁了之后,多个线程再去争抢CPU的时间片
        }
    }

    //同步方法:我们可以把一个方法用synchronized这个关键字修饰,来封装一段代码,来解决线程安全问题
    //同步方法:默认用的锁对象是this
    public synchronized void maiPiao() {
        //System.out.println(this);
        if (piao >= 1) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "正在出售第:" + (piao--) + " 张票");
        }
    }
}

lock锁

为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock

Lock和ReentrantLock
	void lock() 加锁 
	void unlock() 释放锁 
package org.westos.demo97;
import java.util.concurrent.locks.ReentrantLock;

public class CellRunnable implements Runnable {
    //这个票让三个线程共享
    static int piao = 100; //共享数据

    //newlock锁对象
    static ReentrantLock lock=new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            // 假如就剩最后一张票  int piao=1;
            //th1 th2 th3
            //加锁
            lock.lock();
            try {
                if (piao >= 1) {
                    //模拟一下真实的售票环境,有网络延迟。
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在出售第:" + (piao--) + " 张票");
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //释放锁 不管有没有遇到异常,锁必须释放
                lock.unlock();
            }
        }
    }
}

死锁

如果出现了同步嵌套,就容易产生死锁问题
是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象

特点:
	不出现异常
	不会出现错误
	程序一直僵持在呢里
package org.westos.demo99;

public class MyThread extends Thread {
    //标记
    boolean flag;

    public MyThread(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        if (flag) {
            synchronized (ObjectUtils.objA) {
                System.out.println("true 线程持有了objA锁,进来执行了AAAA");
                synchronized (ObjectUtils.objB) {
                    System.out.println("true 线程持有了objB锁,进来执行了BBB");
                }
            }
        } else {
            synchronized (ObjectUtils.objB) {
                System.out.println("false线程持有了objB锁,进来执行BBB");
                synchronized (ObjectUtils.objA) {
                    System.out.println("false 线程持有了objA锁,进来执行了AAA");
                }
            }
        }
    }
}

interface ObjectUtils {
    //创建两个对象,来充当两把锁对象
    public static final Object objA=new Object();
    public static final Object objB = new Object();
}

class MyTest2{
    public static void main(String[] args) throws InterruptedException {

        MyThread th1 = new MyThread(true);
        MyThread th2 = new MyThread(false);
        th1.start();
        // Thread.sleep(50);
        th2.start();
    }
}
public class DeadLock {
    public static void main(String[] args) {
        Object o1 = new Object();
        Object o2 = new Object();

        // t1和t2两个线程共享o1,o2
        Thread t1 = new MyThread1(o1,o2);
        Thread t2 = new MyThread2(o1,o2);

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

class MyThread1 extends Thread{
    Object o1;
    Object o2;
    public MyThread1(Object o1,Object o2){
        this.o1 = o1;
        this.o2 = o2;
    }
    public void run(){
        synchronized (o1){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o2){

            }
        }
    }
}

class MyThread2 extends Thread {
    Object o1;
    Object o2;
    public MyThread2(Object o1,Object o2){
        this.o1 = o1;
        this.o2 = o2;
    }
    public void run(){
        synchronized (o2){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o1){

            }
        }
    }
}

以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值