- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章聊聊Java中并发编程的十个坑由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
对于从事后端开发的同学来说,并发编程肯定再熟悉不过了.
说实话,在java中并发编程是一大难点,至少我是这么认为的。不光理解起来比较费劲,使用起来更容易踩坑.
不信,让继续往下面看.
今天重点跟大家一起聊聊并发编程的10个坑,希望对你有帮助.
在java8之前,我们对时间的格式化处理,一般都是用的SimpleDateFormat类实现的。例如:
public class SimpleDateFormatService { public Date time(String time) throws ParseException { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return dateFormat.parse(time); }}
如果你真的这样写,是没问题的.
就怕哪天抽风,你觉得dateFormat是一段固定的代码,应该要把它抽取成常量.
于是把代码改成下面的这样:
public class SimpleDateFormatService { private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public Date time(String time) throws ParseException { return dateFormat.parse(time); }}
dateFormat对象被定义成了静态常量,这样就能被所有对象共用.
如果只有一个线程调用time方法,也不会出现问题.
但Serivce类的方法,往往是被Controller类调用的,而Controller类的接口方法,则会被tomcat的线程池调用。换句话说,可能会出现多个线程调用同一个Controller类的同一个方法,也就是会出现多个线程会同时调用time方法的情况.
而time方法会调用SimpleDateFormat类的parse方法:
public Date parse(String text, ParsePosition pos) { ... Date parsedDate; try { parsedDate = calb.establish(calendar).getTime(); ... } catch (IllegalArgumentException e) { pos.errorIndex = start; pos.index = oldStart; return null; } return parsedDate;}
该方法会调用establish方法:
Calendar establish(Calendar cal) { ... //1.清空数据 cal.clear(); //2.设置时间 cal.set(...); //3.返回 return cal;}
其中的步骤1、2、3是非原子操作.
但如果cal对象是局部变量还好,坏就坏在parse方法调用establish方法时,传入的calendar是SimpleDateFormat类的父类DateFormat的成员变量:
public abstract class DateFormat extends Forma { .... protected Calendar calendar; ...}
这样就可能会出现多个线程,同时修改同一个对象即:dateFormat,他的同一个成员变量即:Calendar值的情况.
这样可能会出现,某个线程设置好了时间,又被其他的线程修改了,从而出现时间错误的情况.
那么,如何解决这个问题呢?
单例模式无论在实际工作,还是在面试中,都出现得比较多.
我们都知道,单例模式有:饿汉模式和懒汉模式两种.
饿汉模式代码如下:
public class SimpleSingleton { //持有自己类的引用 private static final SimpleSingleton INSTANCE = new SimpleSingleton(); //私有的构造方法 private SimpleSingleton() { } //对外提供获取实例的静态方法 public static SimpleSingleton getInstance() { return INSTANCE; }}
使用饿汉模式的好处是:没有线程安全的问题,但带来的坏处也很明显.
private static final SimpleSingleton INSTANCE = new SimpleSingleton();
一开始就实例化对象了,如果实例化过程非常耗时,并且最后这个对象没有被使用,不是白白造成资源浪费吗?
还真是啊.
这个时候你也许会想到,不用提前实例化对象,在真正使用的时候再实例化不就可以了?
这就是我接下来要介绍的:懒汉模式.
具体代码如下:
public class SimpleSingleton2 { private static SimpleSingleton2 INSTANCE; private SimpleSingleton2() { } public static SimpleSingleton2 getInstance() { if (INSTANCE == null) { INSTANCE = new SimpleSingleton2(); } return INSTANCE; }}
示例中的INSTANCE对象一开始是空的,在调用getInstance方法才会真正实例化.
嗯,不错不错。但这段代码还是有问题.
假如有多个线程中都调用了getInstance方法,那么都走到 if (INSTANCE == null) 判断时,可能同时成立,因为INSTANCE初始化时默认值是null。这样会导致多个线程中同时创建INSTANCE对象,即INSTANCE对象被创建了多次,违背了只创建一个INSTANCE对象的初衷.
为了解决饿汉模式和懒汉模式各自的问题,于是出现了:双重检查锁.
具体代码如下:
public class SimpleSingleton4 { private static SimpleSingleton4 INSTANCE; private SimpleSingleton4() { } public static SimpleSingleton4 getInstance() { if (INSTANCE == null) { synchronized (SimpleSingleton4.class) { if (INSTANCE == null) { INSTANCE = new SimpleSingleton4(); } } } return INSTANCE; }}
需要在synchronized前后两次判空.
但我要告诉你的是:这段代码有漏洞的.
有什么问题?
public static SimpleSingleton4 getInstance() { if (INSTANCE == null) {//1 synchronized (SimpleSingleton4.class) {//2 if (INSTANCE == null) {//3 INSTANCE = new SimpleSingleton4();//4 } } } return INSTANCE;//5 }
getInstance方法的这段代码,我是按1、2、3、4、5这种顺序写的,希望也按这个顺序执行.
但是java虚拟机实际上会做一些优化,对一些代码指令进行重排。重排之后的顺序可能就变成了:1、3、2、4、5,这样在多线程的情况下同样会创建多次实例。重排之后的代码可能如下:
public static SimpleSingleton4 getInstance() { if (INSTANCE == null) {//1 if (INSTANCE == null) {//3 synchronized (SimpleSingleton4.class) {//2 INSTANCE = new SimpleSingleton4();//4 } } } return INSTANCE;//5 }
原来如此,那有什么办法可以解决呢?
答:可以在定义INSTANCE是加上volatile关键字。具体代码如下:
public class SimpleSingleton7 { private volatile static SimpleSingleton7 INSTANCE; private SimpleSingleton7() { } public static SimpleSingleton7 getInstance() { if (INSTANCE == null) { synchronized (SimpleSingleton7.class) { if (INSTANCE == null) { INSTANCE = new SimpleSingleton7(); } } } return INSTANCE; }}
volatile关键字可以保证多个线程的可见性,但是不能保证原子性。同时它也能禁止指令重排.
双重检查锁的机制既保证了线程安全,又比直接上锁提高了执行效率,还节省了内存空间.
此外,如果你想了解更多单例模式的细节问题,可以看看我的另一篇文章《单例模式,真不简单》 。
从前面我们已经知道volatile,是一个非常不错的关键字,它能保证变量在多个线程中的可见性,它也能禁止指令重排,但是不能保证原子性.
使用volatile关键字禁止指令重排,前面已经说过了,这里就不聊了.
可见性主要体现在:一个线程对某个变量修改了,另一个线程每次都能获取到该变量的最新值.
先一起看看反例:
public class VolatileTest extends Thread { private boolean stopFlag = false; public boolean isStopFlag() { return stopFlag; } public void run() { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } stopFlag = true; System.out.println(Thread.currentThread().getName() + " stopFlag = " + stopFlag); } public static void main(String[] args) { VolatileTest vt = new VolatileTest(); vt.start(); while (true) { if (vt.isStopFlag()) { System.out.println("stop"); break; } } }}
上面这段代码中,VolatileTest是一个Thread类的子类,它的成员变量stopFlag默认是false,在它的run方法中修改成了true.
然后在main方法的主线程中,用vt.isStopFlag()方法判断,如果它的值是true时,则打印stop关键字.
那么,如何才能让stopFlag的值修改了,在主线程中通过vt.isStopFlag()方法,能够获取最新的值呢?
正例如下:
public class VolatileTest extends Thread { private volatile boolean stopFlag = false; public boolean isStopFlag() { return stopFlag; } public void run() { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } stopFlag = true; System.out.println(Thread.currentThread().getName() + " stopFlag = " + stopFlag); } public static void main(String[] args) { VolatileTest vt = new VolatileTest(); vt.start(); while (true) { if (vt.isStopFlag()) { System.out.println("stop"); break; } } }}
用volatile关键字修饰stopFlag即可.
下面重点说说volatile的原子性问题.
使用多线程给count加1,代码如下:
public class VolatileTest { public volatile int count = 0; public void add() { count++; } public static void main(String[] args) { final VolatileTest test = new VolatileTest(); for (int i = 0; i < 20; i++) { new Thread() { public void run() { for (int j = 0; j < 1000; j++) { test.add(); } } ; }.start(); } while (Thread.activeCount() > 2) { //保证前面的线程都执行完 Thread.yield(); } System.out.println(test.count); }}
执行结果每次都不一样,但可以肯定的是count值每次都小于20000,比如:19999.
这个例子中count是成员变量,虽说被定义成了volatile的,但由于add方法中的count++是非原子操作。在多线程环境中,count++的数据可能会出现问题.
由此可见,volatile不能保证原子性.
那么,如何解决这个问题呢?
答:使用synchronized关键字.
改造后的代码如下:
public class VolatileTest { public int count = 0; public synchronized void add() { count++; } public static void main(String[] args) { final VolatileTest test = new VolatileTest(); for (int i = 0; i < 20; i++) { new Thread() { public void run() { for (int j = 0; j < 1000; j++) { test.add(); } } ; }.start(); } while (Thread.activeCount() > 2) { //保证前面的线程都执行完 Thread.yield(); } System.out.println(test.count); }}
死锁可能是大家都不希望遇到的问题,因为一旦程序出现了死锁,如果没有外力的作用,程序将会一直处于资源竞争的假死状态中.
死锁代码如下:
public class DeadLockTest { public static String OBJECT_1 = "OBJECT_1"; public static String OBJECT_2 = "OBJECT_2"; public static void main(String[] args) { LockA lockA = new LockA(); new Thread(lockA).start(); LockB lockB = new LockB(); new Thread(lockB).start(); }} class LockA implements Runnable { public void run() { synchronized (DeadLockTest.OBJECT_1) { try { Thread.sleep(500); synchronized (DeadLockTest.OBJECT_2) { System.out.println("LockA"); } } catch (InterruptedException e) { e.printStackTrace(); } } }} class LockB implements Runnable { public void run() { synchronized (DeadLockTest.OBJECT_2) { try { Thread.sleep(500); synchronized (DeadLockTest.OBJECT_1) { System.out.println("LockB"); } } catch (InterruptedException e) { e.printStackTrace(); } } }}
一个线程在获取OBJECT_1锁时,没有释放锁,又去申请OBJECT_2锁。而刚好此时,另一个线程获取到了OBJECT_2锁,也没有释放锁,去申请OBJECT_1锁。由于OBJECT_1和OBJECT_2锁都没有释放,两个线程将一起请求下去,陷入死循环,即出现死锁的情况.
那么如果避免死锁问题呢?
出现死锁的情况,有可能是像上面那样,锁范围太大了导致的.
那么解决办法就是缩小锁的范围.
具体代码如下:
class LockA implements Runnable { public void run() { synchronized (DeadLockTest.OBJECT_1) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (DeadLockTest.OBJECT_2) { System.out.println("LockA"); } }} class LockB implements Runnable { public void run() { synchronized (DeadLockTest.OBJECT_2) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (DeadLockTest.OBJECT_1) { System.out.println("LockB"); } }}
在获取OBJECT_1锁的代码块中,不包含获取OBJECT_2锁的代码。同时在获取OBJECT_2锁的代码块中,也不包含获取OBJECT_1锁的代码.
出现死锁的情况说白了是,一个线程获取锁的顺序是:OBJECT_1和OBJECT_2。而另一个线程获取锁的顺序刚好相反为:OBJECT_2和OBJECT_1.
那么,如果我们能保证每次获取锁的顺序都相同,就不会出现死锁问题.
具体代码如下:
class LockA implements Runnable { public void run() { synchronized (DeadLockTest.OBJECT_1) { try { Thread.sleep(500); synchronized (DeadLockTest.OBJECT_2) { System.out.println("LockA"); } } catch (InterruptedException e) { e.printStackTrace(); } } }} class LockB implements Runnable { public void run() { synchronized (DeadLockTest.OBJECT_1) { try { Thread.sleep(500); synchronized (DeadLockTest.OBJECT_2) { System.out.println("LockB"); } } catch (InterruptedException e) { e.printStackTrace(); } } }}
两个线程,每个线程都是先获取OBJECT_1锁,再获取OBJECT_2锁.
在java中除了使用synchronized关键字,给我们所需要的代码块加锁之外,还能通过Lock关键字加锁.
使用synchronized关键字加锁后,如果程序执行完毕,或者程序出现异常时,会自动释放锁.
但如果使用Lock关键字加锁后,需要开发人员在代码中手动释放锁.
例如:
public class LockTest { private final ReentrantLock rLock = new ReentrantLock(); public void fun() { rLock.lock(); try { System.out.println("fun"); } finally { rLock.unlock(); } }}
代码中先创建一个ReentrantLock类的实例对象rLock,调用它的lock方法加锁。然后执行业务代码,最后再finally代码块中调用unlock方法.
但如果你没有在finally代码块中,调用unlock方法手动释放锁,线程持有的锁将不会得到释放.
HashMap在实际的工作场景中,使用频率还是挺高的,比如:接收参数,缓存数据,汇总数据等等.
但如果你在多线程的环境中使用HashMap,可能会导致非常严重的后果.
public class HashMapService { private Map<Long, Object> hashMap = new HashMap<>(); public void add(User user) { hashMap.put(user.getId(), user.getName()); }}
在HashMapService类中定义了一个HashMap的成员变量,在add方法中往HashMap中添加数据。在controller层的接口中调用add方法,会使用tomcat的线程池去处理请求,就相当于在多线程的场景下调用add方法.
在jdk1.7中,HashMap使用的数据结构是:数组+链表。如果在多线程的情况下,不断往HashMap中添加数据,它会调用resize方法进行扩容。该方法在复制元素到新数组时,采用的头插法,在某些情况下,会导致链表会出现死循环.
死循环最终结果会导致:内存溢出.
此外,如果HashMap中数据非常多,会导致链表很长。当查找某个元素时,需要遍历某个链表,查询效率不太高.
为此,jdk1.8之后,将HashMap的数据结构改成了:数组+链表+红黑树.
如果同一个数组元素中的数据项小于8个,则还是用链表保存数据。如果大于8个,则自动转换成红黑树.
为什么要用红黑树?
答:链表的时间复杂度是O(n),而红黑树的时间复杂度是O(logn),红黑树的复杂度是优于链表的.
既然这样,为什么不直接使用红黑树?
答:树节点所占存储空间是链表节点的两倍,节点少的时候,尽管在时间复杂度上,红黑树比链表稍微好一些。但是由于红黑树所占空间比较大,HashMap综合考虑之后,认为节点数量少的时候用占存储空间更多的红黑树不划算.
jdk1.8中HashMap就不会出现死循环?
答:错,它在多线程环境中依然会出现死循环。在扩容的过程中,在链表转换为树的时候,for循环一直无法跳出,从而导致死循环.
那么,如果想多线程环境中使用HashMap该怎么办呢?
答:使用ConcurrentHashMap.
我们都知道jdk1.5之后,提供了ThreadPoolExecutor类,用它可以自定义线程池.
线程池的好处有很多,比如:
当然jdk为了我们使用更便捷,专门提供了:Executors类,给我们快速创建线程池.
该类中包含了很多静态方法:
在高并发的场景下,如果大家使用这些静态方法创建线程池,会有一些问题.
那么,我们一起看看有哪些问题?
那我们该怎办呢?
优先推荐使用ThreadPoolExecutor类,我们自定义线程池.
具体代码如下:
ExecutorService threadPool = new ThreadPoolExecutor( 8, //corePoolSize线程池中核心线程数 10, //maximumPoolSize 线程池中最大线程数 60, //线程池中线程的最大空闲时间,超过这个时间空闲线程将被回收 TimeUnit.SECONDS,//时间单位 new ArrayBlockingQueue(500), //队列 new ThreadPoolExecutor.CallerRunsPolicy()); //拒绝策略
顺便说一下,如果是一些低并发场景,使用Executors类创建线程池也未尝不可,也不能完全一棍子打死。在这些低并发场景下,很难出现OOM问题,所以我们需要根据实际业务场景选择.
之前在java并发编程中实现异步功能,一般是需要使用线程或者线程池.
线程池的底层也是用的线程.
而实现一个线程,要么继承Thread类,要么实现Runnable接口,然后在run方法中写具体的业务逻辑代码.
开发spring的大神们,为了简化这类异步操作,已经帮我们把异步功能封装好了。spring中提供了@Async注解,我们可以通过它即可开启异步功能,使用起来非常方便.
具体做法如下:
在springboot的启动类上面加上@EnableAsync注解.
public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
在需要执行异步调用的业务方法加上@Async注解.
public class CategoryService { public void add(Category category) { //添加分类 }}
在controller方法中调用这个业务方法.
"/category") public class CategoryController { private CategoryService categoryService; ("/add") public void add( category) { categoryService.add(category); }}(
这样就能开启异步功能了.
是不是很easy?
但有个坏消息是:用@Async注解开启的异步功能,会调用AsyncExecutionAspectSupport类的doSubmit方法.
默认情况会走else逻辑.
而else的逻辑最终会调用doExecute方法:
protected void doExecute(Runnable task) { Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task)); thread.start();}
我去,这不是每次都会创建一个新线程吗?
没错,使用@Async注解开启的异步功能,默认情况下,每次都会创建一个新线程.
如果在高并发的场景下,可能会产生大量的线程,从而导致OOM问题.
建议大家在@Async注解开启的异步功能时,请别忘了定义一个线程池.
在并发编程中,自旋锁想必大家都已经耳熟能详了.
自旋锁有个非常经典的使用场景就是:CAS(即比较和交换),它是一种无锁化思想(说白了用了一个死循环),用来解决高并发场景下,更新数据的问题.
而atomic包下的很多类,比如:AtomicInteger、AtomicLong、AtomicBoolean等,都是用CAS实现的.
我们以AtomicInteger类为例,它的incrementAndGet没有每次都给变量加1.
public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1;}
它的底层就是用的自旋锁实现的:
public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5;}
在do...while死循环中,不停进行数据的比较和交换,如果一直失败,则一直循环重试.
如果在高并发的情况下,compareAndSwapInt会很大概率失败,因此导致了此处cpu不断的自旋,这样会严重浪费cpu资源.
那么,如果解决这个问题呢?
答:使用LockSupport类的parkNanos方法.
具体代码如下:
private boolean compareAndSwapInt2(Object var1, long var2, int var4, int var5) { if(this.compareAndSwapInt(var1,var2,var4, var5)) { return true; } else { LockSupport.parkNanos(10); return false; } }
当cas失败之后,调用LockSupport类的parkNanos方法休眠一下,相当于调用了Thread.Sleep方法。这样能够有效的减少频繁自旋导致cpu资源过度浪费的问题.
在java中保证线程安全的技术有很多,可以使用synchroized、Lock等关键字给代码块加锁.
但是它们有个共同的特点,就是加锁会对代码的性能有一定的损耗.
其实,在jdk中还提供了另外一种思想即:用空间换时间.
没错,使用ThreadLocal类就是对这种思想的一种具体体现.
ThreadLocal为每个使用变量的线程提供了一个独立的变量副本,这样每一个线程都能独立地改变自己的副本,而不会影响其它线程所对应的副本.
ThreadLocal的用法大致是这样的:
先创建一个CurrentUser类,其中包含了ThreadLocal的逻辑.
public class CurrentUser { private static final ThreadLocal<UserInfo> THREA_LOCAL = new ThreadLocal(); public static void set(UserInfo userInfo) { THREA_LOCAL.set(userInfo); } public static UserInfo get() { THREA_LOCAL.get(); } public static void remove() { THREA_LOCAL.remove(); }}
在业务代码中调用CurrentUser类.
public void doSamething(UserDto userDto) { UserInfo userInfo = convert(userDto); CurrentUser.set(userInfo); ... //业务代码 UserInfo userInfo = CurrentUser.get(); ...}
在业务代码的第一行,将userInfo对象设置到CurrentUser,这样在业务代码中,就能通过CurrentUser.get()获取到刚刚设置的userInfo对象。特别是对业务代码调用层级比较深的情况,这种用法非常有用,可以减少很多不必要传参.
但在高并发的场景下,这段代码有问题,只往ThreadLocal存数据,数据用完之后并没有及时清理.
ThreadLocal即使使用了WeakReference(弱引用)也可能会存在内存泄露问题,因为 entry对象中只把key(即threadLocal对象)设置成了弱引用,但是value值没有.
那么,如何解决这个问题呢?
public void doSamething(UserDto userDto) { UserInfo userInfo = convert(userDto); try{ CurrentUser.set(userInfo); ... //业务代码 UserInfo userInfo = CurrentUser.get(); ... } finally { CurrentUser.remove(); }}
需要在finally代码块中,调用remove方法清理没用的数据.
原文地址:https://mp.weixin.qq.com/s/lJidWmVNLlXpWLeGLXWMxQ 。
最后此篇关于聊聊Java中并发编程的十个坑的文章就讲到这里了,如果你想了解更多关于聊聊Java中并发编程的十个坑的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试打印 timeval 类型的值。实际上我可以打印它,但我收到以下警告: 该行有多个标记 格式“%ld”需要“long int”类型,但参数 2 的类型为“struct timeval” 程序
我正在编写自己的 unix 终端,但在执行命令时遇到问题: 首先,我获取用户输入并将其存储到缓冲区中,然后我将单词分开并将它们存储到我的 argv[] 数组中。IE命令是“firefox”以启动存储在
我是 CUDA 的新手。我有一个关于一个简单程序的问题,希望有人能注意到我的错误。 __global__ void ADD(float* A, float* B, float* C) { con
我有一个关于 C 语言 CGI 编程的一般性问题。 我使用嵌入式 Web 服务器来处理 Web 界面。为此,我在服务器中存储了一个 HTML 文件。在此 HTML 文件中包含 JavaScript 和
**摘要:**在代码的世界中,是存在很多艺术般的写法,这可能也是部分程序员追求编程这项事业的内在动力。 本文分享自华为云社区《【云驻共创】用4种代码中的艺术试图唤回你对编程的兴趣》,作者: break
我有一个函数,它的任务是在父对象中创建一个变量。我想要的是让函数在调用它的级别创建变量。 createVariable testFunc() [1] "test" > testFunc2() [1]
以下代码用于将多个连续的空格替换为1个空格。虽然我设法做到了,但我对花括号的使用感到困惑。 这个实际上运行良好: #include #include int main() { int ch, la
我正在尝试将文件写入磁盘,然后自动重新编译。不幸的是,某事似乎不起作用,我收到一条我还不明白的错误消息(我是 C 初学者 :-)。如果我手动编译生成的 hello.c,一切正常吗?! #include
如何将指针值传递给结构数组; 例如,在 txt 上我有这个: John Doe;xxxx@hotmail.com;214425532; 我的代码: typedef struct Person{
我尝试编写一些代码来检索 objectID,结果是 2B-06-01-04-01-82-31-01-03-01-01 . 这个值不正确吗? // Send a SysObjectId SNMP req
您好,提前感谢您的帮助, (请注意评论部分以获得更多见解:即,以下示例中的成本列已添加到此问题中;西蒙提供了一个很好的答案,但成本列本身并未出现在他的数据响应中,尽管他提供的功能与成本列一起使用) 我
我想知道是否有人能够提出一些解决非线性优化问题的软件包的方法,而非线性优化问题可以为优化解决方案提供整数变量?问题是使具有相等约束的函数最小化,该函数受某些上下边界约束的约束。 我已经在R中使用了'n
我是 R 编程的初学者,正在尝试向具有 50 列的矩阵添加一个额外的列。这个新列将是该行中前 10 个值的平均值。 randomMatrix <- generateMatrix(1,5000,100,
我在《K&R II C 编程 ANSI C》一书中读到,“>>”和“0; nwords--) sum += *buf++; sum = (sum >>
当下拉列表的选择发生变化时,我想: 1) 通过 div 在整个网站上显示一些 GUI 阻止覆盖 2)然后处理一些代码 3) 然后隐藏叠加层。 问题是,当我在事件监听器函数中编写此逻辑时,将执行 onC
我正在使用 Clojure 和 RESTEasy 设计 JAX-RS REST 服务器. 据我了解,用 Lisp 系列语言编写的应用程序比用“传统”命令式语言编写的应用程序更多地构建为“特定于领域的语
我目前正在研究一种替代出勤监控系统作为一项举措。目前,我设计的用户表单如下所示: Time Stamp Userform 它的工作原理如下: 员工将选择他/她将使用的时间戳类型:开始时间、超时、第一次
我是一名学生,试图自学编程,从在线资源和像您这样的人那里获得帮助。我在网上找到了一个练习来创建一个小程序来执行此操作: 编写一个程序,读取数字 a 和 b(长整型)并列出 a 和 b 之间有多少个数字
我正在尝试编写一个 shell 程序,给定一个参数,打印程序的名称和参数中的每个奇数词(即,不是偶数词)。但是,我没有得到预期的结果。在跟踪我的程序时,我注意到,尽管奇数词(例如,第 5 个词,5 %
只是想知道是否有任何 Java API 可以让您控制台式机/笔记本电脑外壳上的 LED? 或者,如果不可能,是否有可能? 最佳答案 如果你说的是前面的 LED 指示电源状态和 HDD 繁忙状态,恐怕没
我是一名优秀的程序员,十分优秀!