记录多线程

线程和进程的基本概念

程序:
       用某种语言编写的一段指令的集合,静态代码静态对象
进程:
       是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间
线程:
       是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行 . 一个进程最少有一个线程 ,线程实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分 成若干个线程
 

并发与并行 &&同步与异步

并发:一个CPU同时执行多个任务

并行:多个CPU同时执行多个不同任务

前者是逻辑上的同时发生,后者是物理上的同时发生

同步:排队执行 , 效率低但是安全。

异步:同时执行 , 效率高但是数据不安全。

线程的调度方式 

分时调度:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。

抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性)

注意:多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的 使

用率更高。

   

 线程的相关API

//获取当前线程的名字
Thread.currentThread().getName()

1.start():1.启动当前线程2.调用线程中的run方法
2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3.currentThread():静态方法,返回执行当前代码的线程
4.getName():获取当前线程的名字
5.setName():设置当前线程的名字
6.yield():主动释放当前线程的执行权
7.join():在线程中插入执行另一个线程,该线程被阻塞,直到插入执行的线程完全执行完毕以后,该线程才继续执行下去
8.stop():过时方法。当执行此方法时,强制结束当前线程。
9.sleep(long millitime):线程休眠一段时间
10.isAlive():判断当前线程是否存活
 

多线程的创建方式

1.继承Thread

1.创建一个集成于Thread类的子类 (通过ctrl+o(override)输入run查找run方法)
2.重写Thread类的run()方法
3.创建Thread子类的对象
4.通过此对象调用start()方法

创建线程的方式: MyThread myThread = new MyThread();

2.实现Runnable

相比较Thread而言,通过实现runnable的方式可以更容易地实现资源共享,并且接口可以多实现且还能再继承其他类.

面向接口编程, 松耦合设计
不能独立运行, 需绑定在Thread实例上运行
主线程不能监控子线程何时结束, 也不能获取子线程返回结果
切记启动异步线程的方式是调用start()方法, 而非调用run()方法.
主线程不能捕获子线程的抛出的异常, 通常会在run()方法中包裹一个最大的try-catch,自行处理异常

步骤

1.创建一个实现了Runable接口的类
2.实现类去实现Runnable中的抽象方法:run()
3.创建实现类的对象
4.将此对象作为参数传递到Thread类中的构造器中,创建Thread类的对象
5.通过Thread类的对象调用start()

	package com.example.paoduantui.Thread;
	
	public class ThreadDemo01 {
	    
	    public static  void main(String[] args){
	        window1 w = new window1();
	        
	        //虽然有三个线程,但是只有一个窗口类实现的Runnable方法,由于三个线程共用一个window对象,所以自动共用100张票
	        
	        Thread t1=new Thread(w);
	        Thread t2=new Thread(w);
	        Thread t3=new Thread(w);
	
	        t1.setName("窗口1");
	        t2.setName("窗口2");
	        t3.setName("窗口3");
	        
	        t1.start();
	        t2.start();
	        t3.start();
	    }
	}
	
	class window1 implements Runnable{
	    
	    private int ticket = 100;
	
	    @Override
	    public void run() {
	        while(true){
	            if(ticket>0){
	//                try {
	//                    sleep(100);
	//                } catch (InterruptedException e) {
	//                    e.printStackTrace();
	//                }
	                System.out.println(Thread.currentThread().getName()+"当前售出第"+ticket+"张票");
	                ticket--;
	            }else{
	                break;
	            }
	        }
	    }
	}

 3.实现callable接口方式:

Runnable与Callable

接口定义
//Callable 接口
public interface Callable<V> {
V call() throws Exception;
}
//Runnable 接口
public interface Runnable {
public abstract void run();
}

 callable使用步骤

1. 编写类实现 Callable 接口 , 实现 call 方法
class XXX implements Callable<T> {
@Override
        public <T> call() throws Exception {
          return T;
     }
}
2. 创建 FutureTask 对象 , 并传入第一步编写的 Callable 类对象
    FutureTask<Integer> future = new FutureTask<>(callable);
3. 通过 Thread, 启动线程
new Thread(future).start();

Runnable与Callable 相同点与不同点


相同:

都是接口

都可以编写多线程程序
都采用 Thread.start() 启动线程
不同:
Runnable 没有返回值; Callable 可以返回执行结果
Callable 接口的 call() 允许抛出异常; Runnable run() 不能抛出
注意:
Callalble 接口支持返回执行结果,需要调用 FutureTask.get() 得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。

 4.线程池方式

线程池  Executors

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程 就会大大降低 系统的效率,因为频繁创建线程和销毁线程需要时间. 线程池就是一个容纳多个线程的容 器,池中的线程可以反复使用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。
好处:
降低资源消耗。
提高响应速度。
提高线程的可管理性。

 Java中的四种线程池 . ExecutorService

 缓存线程池:ExecutorService service =Executors.newCachedThreadPool();

 定长线程池:ExecutorService service =Executors.newFixedThreadPool();

 单线程线程池:ExecutorService service =Executors.newSingleThreadExecutor();

 周期性任务定长线程池:

ScheduledExecutorService service = Executors.newScheduledThreadPool();

线程的生命周期:

 

线程通信的常用方法:

 

 

 线程的安全问题:

线程安全问题是指,多个线程对同一个共享数据进行操作时,线程没来得及更新共享数据,从而导致另外线程没得到最新的数据,从而产生线程安全问题。

 线程安全解决方法:

 方式1:同步代码块:

使用同步监视器(锁)
Synchronized(同步监视器){
//需要被同步的代码
}

方式2:同步方法: 

使用同步方法,对方法进行synchronized关键字修饰
将同步代码块提取出来成为一个方法,用synchronized关键字修饰此方法。
对于runnable接口实现多线程,只需要将同步方法用synchronized修饰
而对于继承自Thread方式,需要将同步方法用static和synchronized修饰,因为对象不唯一(锁不唯一)
 

注意

1.同步方法仍然涉及到同步监视器,只是不需要我们显示的声明。
2.非静态的同步方法,同步监视器是this
静态的同步方法,同步监视器是当前类本身。继承自Thread。class

方式3:显式锁lock:

package com.example.paoduantui.Thread;


import java.util.concurrent.locks.ReentrantLock;

class Window implements Runnable{
    private int ticket = 100;//定义一百张票
    //1.实例化锁
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        
            while (true) {

                //2.调用锁定方法lock
                lock.lock();

                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + "售出第" + ticket + "张票");
                    ticket--;
                } else {
                    break;
                }
            }


        }
}

public class LockTest {

    public static void main(String[] args){
       Window w= new Window();

       Thread t1 = new Thread(w);
       Thread t2 = new Thread(w);
       Thread t3 = new Thread(w);

       t1.setName("窗口1");
       t2.setName("窗口1");
       t3.setName("窗口1");

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

}

Synchronized与lock的异同 

相同:二者都可以解决线程安全问题
不同:synchronized机制在执行完相应的代码逻辑以后,自动的释放同步监视器
lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock())(同时以为着lock的方式更为灵活)

优先使用顺序:
LOCK->同步代码块->同步方法
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Python 中,可以使用 `logging` 模块记录日志。如果需要在多线程环境下记录日志,可以使用 `concurrent_log_handler` 模块来实现。 首先需要安装 `concurrent_log_handler` 模块: ``` pip install concurrent_log_handler ``` 然后,可以使用以下代码来记录日志: ```python import logging from concurrent_log_handler import ConcurrentRotatingFileHandler import threading # 创建日志记录器 logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) # 创建文件处理器 handler = ConcurrentRotatingFileHandler(filename='example.log', mode='a', maxBytes=1024, backupCount=3) handler.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) # 将处理器添加到记录器 logger.addHandler(handler) # 多线记录日志 def worker(): logger.debug('Debug message from thread {0}'.format(threading.current_thread().name)) logger.info('Info message from thread {0}'.format(threading.current_thread().name)) logger.warning('Warning message from thread {0}'.format(threading.current_thread().name)) logger.error('Error message from thread {0}'.format(threading.current_thread().name)) logger.critical('Critical message from thread {0}'.format(threading.current_thread().name)) threads = [] for i in range(10): t = threading.Thread(target=worker) threads.append(t) t.start() for t in threads: t.join() ``` 上面的代码中,创建了一个 `ConcurrentRotatingFileHandler` 类实例化的文件处理器,它可以在多线程环境下安全地写入日志文件。然后,将处理器添加到日志记录器中,并使用多线程来记录日志。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值