并发编程 Java 三把锁(Synchronized、ReentrantLock、ReadWriteLock)

CYC副图通达信指标公式源码.doc 立即下载

Synchronized

synchronized 的 3 种用法:

指定加锁对象(代码块):对给定对象加锁,进入同步代码前要获得给定对象的锁。

void resource1() {
    synchronized ("resource1") {
      System.out.println("作用在同步块中");
    }
  }

直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。

synchronized void resource3() {
    System.out.println("作用在实例方法上");
  }

直接作用于静态方法:相当于对当前类加锁,进入同步代码块前要获得当前类的锁。

static synchronized void resource2() {
      System.out.println("作用在静态方法上");
  }

synchronized 在发生异常的时候会释放锁,这点需要注意一下。


Lock接口:

/**
 * @since 1.5
 * @author Doug Lea
 */
public interface Lock {

    void lock();

    void lockInterruptibly() throws InterruptedException;

    boolean tryLock();

    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    void unlock();

    Condition newCondition();

}

lock():用来获取锁,若锁已被其他线程获取,则需等待
Lock()方法必须主动去释放锁,并且在发生异常时也不会自动释放锁。
使用Lock必须在try…catch…块中进行:

  1. 释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生
  2. 获取锁的操作应该方法try的外面,防止误释放锁。

(如果说在获取锁时发生了异常,那么肯定也会走 finally 代码块,执行lock.unlock();去释放锁,可问题是我还没获取到锁啊!!!)
在 try-finally 外加锁的话,如果因为发生异常导致加锁失败,try-finally 块中的代码不会执行。
相反,如果在 try{ } 代码块中加锁失败,finally 中的代码无论如何都会执行,但是由于当前线程加锁失败并没有持有 lock 对象锁,所以程序会抛出异常。

链接:
https://blog.youkuaiyun.com/u013568373/article/details/98480603?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

unlock():解锁

tryLock():尝试获取锁,若获取不到,立刻返回false;这个方法无论如何都会立即返回,在拿不到锁时不会一直在那等待。

tryLock(long time, TimeUnit unit):在给定的时间里等待锁,超过时间则自动放弃,返回false;在等待期间内拿到了锁,返回true。

lockInterruptibly():
获取某个锁时,如果不能获取到,只有进行等待的情况下,是可以响应中断的;
而用synchronized修饰的话,synchronized 只有2种情况:1继续执行,2保持等待。

 public void method(Lock lock) throws InterruptedException {
        lock.lockInterruptibly();
        try {
            //执行代码
        } catch (Exception e) {
            // 异常处理
        } finally {
            lock.unlock();
        }
    }

一般将lockTry.lockInterruptibly();写在了try{}catch{}之外,原因同上。


Lock 的标准实现是重入锁 ReentrantLock, 和读写锁 ReadWriteLock。

ReentrantLock 重入锁

可重入性:

重入锁ReentrantLock,是支持重进入的锁,该锁能够支持一个线程对资源的重复加锁。
先来一个简单的例子:

package cn.think.in.java.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockText implements Runnable {

  /**
   * Re - entrant - Lock
   * 重入锁,表示在单个线程内,这个锁可以反复进入,也就是说,一个线程可以连续两次获得同一把锁。
   * 如果你不允许重入,将导致死锁。注意,lock 和 unlock 次数一定要相同,如果不同,就会导致死锁和监视器异常。
   *
   * synchronized 只有2种情况:1继续执行,2保持等待。
   */
  static Lock lock = new ReentrantLock();
  static int i;

  public static void main(String[] args) throws InterruptedException {
    LockText lockText = new LockText();
    Thread t1 = new Thread(lockText);
    Thread t2 = new Thread(lockText);
    t1.start();
    t2.start();
    t1.join();
    t2.join();
    System.out.println(i);
  }

  @Override
  public void run() {
    for (int j = 0; j < 1000000; j++) {
      lock.lock();
      try {
        i++;
      } finally {
        // 因为lock 如果发生了异常,是不会释放锁的,所以必须在 finally 块中释放锁
        // synchronized 发生异常会主动释放锁
        lock.unlock();
      }
    }
  }
}

PS:
Synchronized 也支持重进入,但只支持隐式的重进入。

public synchronized void test1() {
	value = value + 1;
	test2();
}
public synchronized void test2() {
	value = value + 1;
}

ReentrantLock与synchronized隐式获取和释放锁相比,它缺少了便捷性,但却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性。
Lock的使用:

Lock lock = new ReentrantLock();
lock.lock();
lock.lock();
try {
	// 业务逻辑
} finally {
	lock.unlock();
	lock.unlock();
}

注意:
1.在finally块中释放锁,保证在获取到锁之后,最终能够被释放。
2.不要将获取锁的过程写在try块中,因为如果在获取锁(自定义锁的实现)时发生了异常,异常抛出的同时,也会导致锁无故释放。

中断响应

synchronized修饰的线程在等待锁,那么只有2种情况:1获取到锁继续执行,2保持等待;
lockInterruptibly 方法修饰的线程,可在获取锁的过程种响应线程中断,那么就会抛出异常。

package cn.think.in.java.lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * ReentrantLock(重入锁)
 *
 * Condition(条件)
 *
 * ReadWriteLock(读写锁)
 */
public class IntLock implements Runnable {

  /**
   * 默认是不公平的锁,设置为 true 为公平锁
   *
   * 公平:在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程;
   * 使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢)
   * 还要注意的是,未定时的 tryLock 方法并没有使用公平设置
   *
   * 不公平:此锁将无法保证任何特定访问顺序
   *
   * 拾遗:1 该类的序列化与内置锁的行为方式相同:一个反序列化的锁处于解除锁定状态,不管它被序列化时的状态是怎样的。
   *      2.此锁最多支持同一个线程发起的 2147483648 个递归锁。试图超过此限制会导致由锁方法抛出的 Error。
   */
  static ReentrantLock lock1 = new ReentrantLock(true);
  static ReentrantLock lock2 = new ReentrantLock();
  int lock;

  /**
   * 控制加锁顺序,方便制造死锁
   * @param lock
   */
  public IntLock(int lock) {
    this.lock = lock;
  }

  /**
   * lockInterruptibly 方法: 获得锁,但优先响应中断
   * tryLock 尝试获得锁,不等待
   * tryLock(long time , TimeUnit unit) 尝试获得锁,等待给定的时间
   */
  @Override
  public void run() {
    try {
      if (lock == 1) {
        // 如果当前线程未被中断,则获取锁。
        lock1.lockInterruptibly();// 即在等待锁的过程中,可以响应中断。
        try {
          Thread.sleep(500);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        // 试图获取 lock 2 的锁
        lock2.lockInterruptibly();
      } else {

        lock2.lockInterruptibly();
        try {
          Thread.sleep(500);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        // 该线程在企图获取 lock1 的时候,会死锁,但被调用了 thread.interrupt 方法,导致中断。中断会放弃锁。
        lock1.lockInterruptibly();
      }

    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      if (lock1.isHeldByCurrentThread()) {
        lock1.unlock();
      }

      // 查询当前线程是否保持此锁。
      if (lock2.isHeldByCurrentThread()) {
        lock2.unlock();
      }

      System.out.println(Thread.currentThread().getId() + ": 线程退出");
    }
  }


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

    /**
     * 这部分代码主要是针对 lockInterruptibly 方法,该方法在线程发生死锁的时候可以中断线程。让线程放弃锁。
     * 而 synchronized 是没有这个功能的, 他要么获得锁继续执行,要么继续等待锁。
     */

    IntLock r1 = new IntLock(1);
    IntLock r2 = new IntLock(2);
    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);
    t1.start();
    t2.start();
    Thread.sleep(1000);
    // 中断其中一个线程(只有线程在等待锁的过程中才有效)
    // 如果线程已经拿到了锁,中断是不起任何作用的。
    // 注意:这点 synchronized 是不能实现此功能的,synchronized 在等待过程中无法中断
    t2.interrupt();
    // t2 线程中断,抛出异常,并放开锁。没有完成任务
    // t1 顺利完成任务。
  }
}

锁申请

trylock(),tryLock(long time, TimeUnit unit)在获取锁如果尝试失败或者超时,线程就放弃获取=锁,这点synchronized 是不支持的,这样可以有效避免死锁。那么,如何使用呢?

package cn.think.in.java.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class TimeLock implements Runnable {

  static ReentrantLock lock = new ReentrantLock(false);

  @Override
  public void run() {
    try {
      // 最多等待5秒,超过5秒返回false,若获得锁,则返回true
      if (lock.tryLock(5, TimeUnit.SECONDS)) {
        // 锁住 6 秒,让下一个线程无法获取锁
        System.out.println("锁住 6 秒,让下一个线程无法获取锁");
        Thread.sleep(6000);
      } else {
        System.out.println("get lock failed");
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      if (lock.isHeldByCurrentThread()) {
        lock.unlock();
      }
    }
  }

  public static void main(String[] args) {
    TimeLock tl = new TimeLock();
    Thread t1 = new Thread(tl);
    Thread t2 = new Thread(tl);

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


  }
}

公平锁和非公平锁

公平锁:不会产生饥饿现象。线程按照等待顺序得到资源
非公平锁:系统在选择锁的时候都是随机的,不会按照某种顺序,比如时间顺序。
synchronized 得到的锁是非公平锁,而ReentrantLock可以自由选择使用公平锁或者非公平锁,同时非公平锁 比 公平锁 更有效率,一般选择非公平锁。

 package cn.think.in.java.lock;

import java.util.concurrent.locks.ReentrantLock;

public class FairLock implements Runnable {

  // 公平锁和非公平锁的结果完全不同
  /*
  * 10 获得锁
    10 获得锁
    10 获得锁
    10 获得锁
    10 获得锁
    10 获得锁
    10 获得锁
    10 获得锁
    10 获得锁
    10 获得锁
    9 获得锁
    9 获得锁
    9 获得锁
    9 获得锁
    9 获得锁
    9 获得锁
    9 获得锁
    9 获得锁
    9 获得锁
    9 获得锁
    ======================下面是公平锁,上面是非公平锁
    10 获得锁
    9 获得锁
    10 获得锁
    9 获得锁
    10 获得锁
    9 获得锁
    10 获得锁
    9 获得锁
    10 获得锁
    9 获得锁
    10 获得锁
    9 获得锁
    10 获得锁
    9 获得锁
    10 获得锁
    9 获得锁
    10 获得锁
    9 获得锁
    10 获得锁
    9 获得锁
    10 获得
  *
  * */
  static ReentrantLock unFairLock = new ReentrantLock(false);
  static ReentrantLock fairLock = new ReentrantLock(true);

  @Override
  public void run() {
    while (true) {
      try {
        fairLock.lock();
        System.out.println(Thread.currentThread().getId() + " 获得锁");
      } finally {
        fairLock.unlock();
      }
    }
  }

  /**
   * 默认是不公平的锁,设置为 true 为公平锁
   *
   * 公平:在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程;
   * 使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢)
   * 还要注意的是,未定时的 tryLock 方法并没有使用公平设置
   *
   * 不公平:此锁将无法保证任何特定访问顺序,但是效率很高
   *
   */
  public static void main(String[] args) {
    FairLock fairLock = new FairLock();
    Thread t1 = new Thread(fairLock, "cxs - t1");
    Thread t2 = new Thread(fairLock, "cxs - t2");
    t1.start();
    t2.start();
  }
}

可以看到,公平锁的打印顺序是完全交替运行,而不公平锁的顺序完全是随机的。

重入锁相比 synchronized 有哪些优势:

  1. 可以在线程等待锁的时候中断线程,synchronized 是做不到的。
  2. 可以尝试获取锁,如果获取不到就放弃,或者设置一定的时间,这也是 synchroized 做不到的。
  3. 可以设置公平锁,synchronized 默认是非公平锁,无法实现公平锁。

重入锁的好搭档-----Condition

synchronized 通过 Object 类的 wait 方法和 notify 方法实现线程之间的通信;
重入锁 ReentrantLock 通过 Condition 接口中的await()、signal()方法进行通信。

public interface Condition {

    void await() throws InterruptedException;

    boolean await(long time, TimeUnit unit) throws InterruptedException;

    long awaitNanos(long nanosTimeout) throws InterruptedException;

    boolean await(long time, TimeUnit unit) throws InterruptedException;

    void awaitUninterruptibly();

    boolean awaitUntil(Date deadline) throws InterruptedException;

    void signal();

    void signalAll();
}

Condition 为不和 Object 类的冲突,使用 await 方法 对应 wait 方法,signal 方法对应 notify 方法。signalAll 方法对应 notifyAll 方法;
awaitUninterruptibly 方法,该方法不会响应线程的中断,但 Object 的 wait 方法是会响应的。 awaitUntil 方法是等待到一个给定的绝对时间,除非调用了 signal 或者中断了。

package cn.think.in.java.lock.condition;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 重入锁的好搭档
 *
 * await 使当前线程等待,同时释放当前锁,当其他线程中使用 signal 或者 signalAll 方法时,线程会重新获得锁并继续执行。
 *       或者当线程被中断时,也能跳出等待,这和 Object.wait 方法很相似。
 * awaitUninterruptibly() 方法与 await 方法基本相同,但是它并不会在等待过程中响应中断。
 * singal() 该方法用于唤醒一个在等待中的线程,相对的 singalAll 方法会唤醒所有在等待的线程,这和 Object.notify 方法很类似。
 */
public class ConditionTest implements Runnable {

  static Lock lock = new ReentrantLock();

  static Condition condition = lock.newCondition();


  @Override
  public void run() {
    try {
      lock.lock();
      // 该线程会释放 lock 的锁,也就是说,一个线程想调用 condition 的方法,必须先获取 lock 的锁。
      // 否则就会像 object 的 wait 方法一样,监视器异常
      condition.await();
      System.out.println("Thread is going on");

    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }

  public static void main(String[] args) throws InterruptedException {
    ConditionTest t = new ConditionTest();
    Thread t1 = new Thread(t);
    t1.start();
    Thread.sleep(1000);
    // 通知 t1 继续执行
    // main 线程必须获取 lock 的锁,才能调用 condition 的方法。否则就是监视器异常,这点和 object 的 wait 方法是一样的。
    lock.lock(); // IllegalMonitorStateException
    // 从 condition 的等待队列中,唤醒一个线程。
    condition.signal();
    lock.unlock();
  }
}

ReadWriteLock:

线程不安全的原因来自于多线程对数据的修改,如果你不修改数据,根本不需要锁。我们完全可以将读写分离,提高性能,在读的时候不使用锁,在写的时候才加入锁。这就是 ReadWriteLock 的设计原理。

public interface ReadWriteLock {
   
    Lock readLock();

    Lock writeLock();
}

读写锁的使用:

package cn.think.in.java.lock;

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo {

  static Lock lock = new ReentrantLock();
  static ReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();

  static Lock readLock = reentrantReadWriteLock.readLock();
  static Lock writeLock = reentrantReadWriteLock.writeLock();

  int value;

  public Object handleRead(Lock lock) throws InterruptedException {
    try {
      lock.lock();
      // 模拟读操作,读操作的耗时越多,读写锁的优势就越明显
      Thread.sleep(1000);
      return value;
    } finally {
      lock.unlock();
    }
  }

  public void handleWrite(Lock lock, int index) throws InterruptedException {
    try {
      lock.lock();
      Thread.sleep(1000); // 模拟写操作
      value = index;

    } finally {
      lock.unlock();
    }
  }

  public static void main(String[] args) {
    final ReadWriteLockDemo demo = new ReadWriteLockDemo();
    Runnable readRunnable = new Runnable() {
      @Override
      public void run() {
        try {
          demo.handleRead(readLock);
//          demo.handleRead(lock);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    };

    Runnable writeRunnable = new Runnable() {
      @Override
      public void run() {
        try {
          demo.handleWrite(writeLock, new Random().nextInt());
//          demo.handleWrite(lock, new Random().nextInt());
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    };

    /**
     * 使用读写锁,这段程序只需要2秒左右
     * 使用普通的锁,这段程序需要20秒左右。
     */

    for (int i = 0; i < 18; i++) {
      new Thread(readRunnable).start();
    }

    for (int i = 18; i < 20; i++) {
      new Thread(writeRunnable).start();
    }


  }

}

两个循环:一个循环开启18个线程去读数据,一个循环开启两个线程去写。如果使用普通的重入锁,将耗时20秒,因为普通的重入锁在读的时候依然是串行的。而如果使用读写锁,只需要2秒,也就是写的时候是串行的。读的时候是并行的,极大的提高了性能。
注意:只要涉及到写都是串行的。比如读写操作,写写操作,都是串行的,只有读读操作是并行的。

ReadWriteLock遵守以下三条基本原则:

  1. 允许多个线程同时读共享变量;
  2. 只允许一个线程写共享变量;
  3. 如果一个写线程正在执行写操作,此时禁止读线程读共享变量。

ReentrantReadWriteLock是ReadWriteLock的一个实现类:

  1. 公平选择性:支持非公平(默认)和公平的锁获取方式,吞吐量还是非公平优于公平。

  2. 重进入:读锁和写锁都支持线程重进入。

  3. 锁降级:遵循获取写锁、获取读锁再释放写锁的次序,写锁能够降级成为读锁。

通达信指标公式源码 指南针BS.doc 立即下载

相关推荐

通达信指标公式源码 三线买卖(主图指标).doc

通达信指标公式源码 三线买卖(主图指标).doc

如何理解Java中眼花缭乱的各种并发锁?

在互联网公司面试中,很多小伙伴都被问到过关于锁的问题。 今天,我给大家一次性把Java并发锁的全家桶彻底讲明白。包括互斥锁、读写锁、重入锁、公平锁、悲观锁、自旋锁、偏向锁等等等等。视频有点长,大家一定要全部看完,保证你会醍醐灌顶。 ...

Tom弹架构 400

仿指南针资金通达信指标源码公式.doc

仿指南针资金通达信指标源码公式.doc

文华财经期货指标公式博易大师软件指标期货多空双轨指标源码

{STICKLINE((C>=O),OPEN,LOW,0,0),COLOR0726CA; STICKLINE((C>=O),CLOSE,HIGH,0,0),COLOR0726CA; STICKLINE((C<O),CLOSE,LOW,0,0),COLORDE9100; STICKLINE((C<O),OPEN,HIGH,0,0),COLORDE9100; STICKLINE((C<O),CLOSE,OPEN,4,0),COLORFF5B00; STICKLINE((C<O),CLOSE,OPEN,3.4,0

2401_87242471的博客 459

通达信指标公式源码 非常牛叉的一个主图指标.doc

通达信指标公式源码 非常牛叉的一个主图指标.doc

仿指南针资金指标_股票_通达信指标_

看股票的资金流入流出情况,捕捉机构资金运作动向。

synchronized ,ReentrantLock,ReadWriteLock 各种锁的区别

Java线程同步机制对比:synchronized是JVM内置锁,自动释放但功能单一;ReentrantLock提供中断、超时等高级功能;ReadWriteLock适用于读多写少场景;StampedLock支持乐观读,性能最佳但使用复杂。选择依据:简单用synchronized,高级功能用ReentrantLock,读多用ReadWriteLock/StampedLock。理解这些锁的底层原理和适用场景是成为高级Java开发的关键。

qq_61723836的博客 721

三线看盘主图指标通达信指标公式源码.doc

三线看盘主图指标通达信指标公式源码.doc

从synchronized到StampedLock:Java锁进化的20年,我们学到了什么?

而乐观锁的做法是:你直接走到书架前,拿起书,翻开最后一页,记下书的“版本号”(时间戳)。想象一下,你正在专心写代码,突然被老板叫去开会,开完会回来又要重新回忆刚才的思路——这个过程的开销远不止开会本身的时间。但是,由于虚拟线程的创建和切换成本极低,我们可以设计更细粒度的并发模型,甚至用“每个请求一个线程”的简单模型替代复杂的线程池和回调机制,从而在更高层次上“避免”了锁的复杂性。每次释放锁,计数器减1。悲观锁的做法是:你先去服务台,说“我要借这本书”,服务台会把书从书架上拿下,锁在柜台里,直到你办完手续。

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

用UltraISO制作镜像以RAW格式刻录系统到U盘后,在Windows上无法识别的解决办法

在这篇文章中,用UltraISO制作镜像后,会使得U盘无法识别!!!那么,如何抹掉U盘的数据,格式化U盘呢?

拥抱具身智能,昇腾Ascend C 2730

实战案例:用多智能体系统模拟房地产市场的架构设计

房地产市场是典型的复杂自适应系统:买方纠结“要不要上车”、卖方盘算“挂多少钱能快速成交”、中介忙着“撮合两边赚佣金”、政府琢磨“怎么调政策稳房价”——每一个参与者的微小决策,最终都会汇聚成“房价暴涨”“成交冰点”这样的宏观现象。传统的计量经济学模型(比如线性回归)假设“所有人都是理性人”,但现实中没人能算清所有变量——你可能因为“同事买了学区房”就跟风,也可能因为“怕失业”而放弃买房。这时候,多智能体系统(MAS)

移动开发前沿的博客 1122

并发编程之 Java 三把锁

前言今天我们继续学习并发。在之前我们学习了 JMM 的知识,知道了在并发编程中,为了保证线程的安全性,需要保证线程的原子性,可见性,有序性。其中,synchronized 高频出现,因为他既保证了原子性,也保证了可见性和有序性。为什么,因为 synchronized 是锁。通过锁,可以让原本并行的任务变成串行。然而如你所见,这也导致了严重的性能受损。因此,不到万不得已,不要使用锁,特别是吞吐量要求特

ignore 1081

Python广度优先搜索BFS - 蓝桥13届省赛污染海域

请问这片N * M海域中有几块是没被污染的独立海域(没被污染的独立海域是指该块海域上下左右被已污染的海域包围,且N * M以外的海域都为已被污染的海域)有一片海域划分为N * M个方格,其中有些海域已被污染(用0表示),有些海域没被污染(用1表示)。第二行开始输入N行,每行M个数字(数字只能为1或者0,1表示没被污染的海域,0表示已被污染的海域)这块4 * 5的海域,有3块海域(绿色)没被污染,因为每一块的上下左右都被污染的海域包围。输出一个整数,表示N * M的海域中有几块是没被污染的独立海域。

m0_69865359的博客 264

java开发中常见锁的使用场景和代码示例

线程同步和并发控制

weixin_45235440的博客 3813

Silly Tavern(酒馆)AI 角色扮演下载与安装教程(Windows本地部署)

SillyTavern是一款开源AI角色扮演前端工具,支持沉浸式对话和长期角色互动。本文详细介绍了在Windows系统F盘部署SillyTavern的完整流程,包括下载项目、安装Node.js和Git环境、配置路径、启动服务等关键步骤,并特别说明非系统盘路径可能遇到的npm安装问题及解决方法。成功启动后,用户可通过浏览器访问本地地址使用该工具进行AI角色扮演互动。

Tan3851的博客 1万+

【ComfyUI】Animate 保留原视频背景角色替换视频生成

本文介绍了智能创作与视频生成的工作流设计,强调其作为围绕业务目标、数据流转和模型能力的有机整体。工作流由数据输入、模型处理、结果合成和输出展示构成,通过节点化连接实现高效复用与扩展。文章重点解析了核心模型(如CLIP Vision、WanVideo等)的功能和协作方式,以及各类节点(输入、处理、控制、输出)的作用。最后展示了工作流在视频角色替换、虚拟试衣等场景的应用价值,并提供了相关开发资源链接。该设计通过模块化实现了灵活适配不同业务需求的能力。

Mr数据杨 1862

Java并发编程:synchronized、Lock、ReentrantLock以及ReadWriteLock的那些事儿

文章目录前言synchronized用法修饰方法修饰实例方法修饰静态方法同步代码块引出LockLock用法子类:ReentrantLock读写分离锁:ReadWriteLockLock和synchronized比较 前言 多线程开发中,同步控制是必不可少的手段。而同步的实现需要用到锁,Java中提供了两种基本的锁,分别是synchronized 和 Lock。两种锁都非常常用,但也各有利弊,下面开...

530

编写一个程序实现顺序表的各种基本运算(假设顺序表的元数基本类型为Char)

/* *Copyright (c) 2016, 烟台大学计算机学院 *All rights reserved. *文件名称:main.cpp *作者:张旺华 *完成日期: 2016 年 7 月 1 日 *版本号:v1.0 *问题描述:编写一个程序实现顺序表的各种基本运算(假设顺序表的元数基本类型为Char) * */ #include #include #include

张旺华的博客 1万+

Synchronized、ReentrantLock、ReadWriteLock 介绍

是包中的一个类,它提供了比 synchronized 更多的功能。是一个接口,它包含一对锁,一个读锁和一个写锁,通过分离读和写操作来提高并发性能。

龙大的博客 641

【Unity大规模RTS/攻城战框架】Large Scale Combat System - RTS Sieges深度解析

本文介绍了Unity专业级大规模RTS战斗框架Large Scale Combat System(LSCS)。该系统通过Job System+Burst技术解决了万人级单位的性能问题,提供完整的RTS操作体系、动态阵型系统、战术AI和攻城战功能。其亮点包括可破坏城门、行走城墙、战术AI配置系统,支持URP渲染管线,适用于Total War风格的大规模兵团对战项目。LSCS不仅提供核心战斗系统,还包含UI、小地图等配套模块,是Unity中少有的专业级RTS解决方案,特别适合需要深度战术玩法和大规模战斗的开发者

2403_88403568的博客 1334

LLM的MCP协议:初识MCP,搭建第一个MCP Server

MCP(Model Context Protocol),是一个开发的协议,标准化了应用程序如何为大模型提供上下文。MCP提供了一个标准的为LLM提供数据、工具的方式,使用MCP会更容易的构建Agent或者是基于LLM的复杂工作流。

Criss@陈磊 2万+

并发编程:浅析重入锁ReentrantLock与读写锁ReadWriteLock

使用还有:当多个线程读写文件时,读操作与读操作之间不会发生冲突。但采用synchronized关键字实现同步时,还是只能一个线程进行读操作,其他读线程只能等待锁的释放而无法进行读操作。因此,需要一种机制来保证多线程都只是进行读操作时,线程之间不会发生冲突(解决方案:ReentrantReadWriteLock)。synchronized无法得知线程是否成功获取到锁 (解决方案:ReentrantLock)。… …

2401_85763997的博客 968

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

ReentrantLock、synchronized 与 ReadWriteLock

ReentrantLock、synchronized 与 ReadWriteLock 一. ReentrantLock ReentrantLock 并不是内置锁 synchronized 的替代方式,而是当 synchronized 加锁机制不适用时,作为一种可选择的高级功能。 ReentrantLock 是 Lock 的实现类,Lock 提供无条件的、可轮询的、定时的以及可中断的锁获取操作,所有...

yxhuang2008的专栏 290

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

ReentrantLock和 synchronized

synchronized 锁升级原理:在锁对象的对象头里面有一个 threadid 字段,在第一次访问的时候 threadid 为空,jvm 让其持有偏向锁,并将 threadid 设置为其线程 id,再次进入的时候会先判断 threadid 是否与其线程 id 一致,如果一致则可以直接使用此对象,如果不一致,则升级偏向锁为 轻量级锁,通过自旋循环一定次数来获取锁,执行一定次数之后,如果还没有正常获取到要使用的对象,此时就会把锁从轻量级升级为重量级锁,此过程就构成了 synchronized 锁的升级。

刘皇叔说Java的博客 816

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

上一篇: Java类加载机制,你理解了吗?
下一篇: ThreadLocal
菜鸟cwt
博客等级 码龄7年 0粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值