Skip to content

Commit 3964a7b

Browse files
committed
Merge pull request #236 from ruby-concurrency/java-extension-for-atomic
[Improvement] - Initial implementation of Concurrent::AtomicBoolean in pure Java
2 parents 5e2ae69 + ceeae16 commit 3964a7b

File tree

5 files changed

+195
-87
lines changed

5 files changed

+195
-87
lines changed

ext/ConcurrentRubyExtService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import java.io.IOException;
2-
2+
33
import org.jruby.Ruby;
44
import org.jruby.runtime.load.BasicLibraryService;
55

66
public class ConcurrentRubyExtService implements BasicLibraryService {
77
public boolean basicLoad(final Ruby runtime) throws IOException {
88
new com.concurrent_ruby.ext.AtomicReferenceLibrary().load(runtime, false);
9+
new com.concurrent_ruby.ext.JavaAtomicBooleanLibrary().load(runtime, false);
10+
new com.concurrent_ruby.ext.JavaAtomicFixnumLibrary().load(runtime, false);
911
return true;
1012
}
1113
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package com.concurrent_ruby.ext;
2+
3+
import java.io.IOException;
4+
import org.jruby.Ruby;
5+
import org.jruby.RubyClass;
6+
import org.jruby.RubyModule;
7+
import org.jruby.RubyObject;
8+
import org.jruby.anno.JRubyClass;
9+
import org.jruby.anno.JRubyMethod;
10+
import org.jruby.runtime.ObjectAllocator;
11+
import org.jruby.runtime.builtin.IRubyObject;
12+
import org.jruby.runtime.load.Library;
13+
import java.util.concurrent.atomic.AtomicBoolean;
14+
import org.jruby.RubyBoolean;
15+
import org.jruby.RubyNil;
16+
import org.jruby.runtime.ThreadContext;
17+
18+
public class JavaAtomicBooleanLibrary implements Library {
19+
20+
public void load(Ruby runtime, boolean wrap) throws IOException {
21+
RubyModule concurrentMod = runtime.defineModule("Concurrent");
22+
RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicBoolean", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR);
23+
atomicCls.defineAnnotatedMethods(JavaAtomicBoolean.class);
24+
}
25+
26+
private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() {
27+
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
28+
return new JavaAtomicBoolean(runtime, klazz);
29+
}
30+
};
31+
32+
@JRubyClass(name = "JavaAtomicBoolean", parent = "Object")
33+
public static class JavaAtomicBoolean extends RubyObject {
34+
35+
private AtomicBoolean atomicBoolean;
36+
private ThreadContext context;
37+
38+
public JavaAtomicBoolean(Ruby runtime, RubyClass metaClass) {
39+
super(runtime, metaClass);
40+
}
41+
42+
@JRubyMethod
43+
public IRubyObject initialize(ThreadContext context, IRubyObject value) {
44+
atomicBoolean = new AtomicBoolean(convertRubyBooleanToJavaBoolean(value));
45+
this.context = context;
46+
return context.nil;
47+
}
48+
49+
@JRubyMethod
50+
public IRubyObject initialize(ThreadContext context) {
51+
atomicBoolean = new AtomicBoolean();
52+
this.context = context;
53+
return context.nil;
54+
}
55+
56+
@JRubyMethod(name = "value")
57+
public IRubyObject value() {
58+
return RubyBoolean.newBoolean(getRuntime(), atomicBoolean.get());
59+
}
60+
61+
@JRubyMethod(name = "true?")
62+
public IRubyObject isAtomicTrue() {
63+
return RubyBoolean.newBoolean(getRuntime(), atomicBoolean.get());
64+
}
65+
66+
@JRubyMethod(name = "false?")
67+
public IRubyObject isAtomicFalse() {
68+
return RubyBoolean.newBoolean(getRuntime(), (atomicBoolean.get() == false));
69+
}
70+
71+
@JRubyMethod(name = "value=")
72+
public IRubyObject setAtomic(IRubyObject newValue) {
73+
atomicBoolean.set(convertRubyBooleanToJavaBoolean(newValue));
74+
return context.nil;
75+
}
76+
77+
@JRubyMethod(name = "make_true")
78+
public IRubyObject makeTrue() {
79+
return RubyBoolean.newBoolean(getRuntime(), atomicBoolean.compareAndSet(false, true));
80+
}
81+
82+
@JRubyMethod(name = "make_false")
83+
public IRubyObject makeFalse() {
84+
return RubyBoolean.newBoolean(getRuntime(), atomicBoolean.compareAndSet(true, false));
85+
}
86+
87+
private boolean convertRubyBooleanToJavaBoolean(IRubyObject newValue) {
88+
if (newValue instanceof RubyBoolean.False || newValue instanceof RubyNil) {
89+
return false;
90+
} else {
91+
return true;
92+
}
93+
}
94+
}
95+
}
96+
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.concurrent_ruby.ext;
2+
3+
import java.io.IOException;
4+
import java.util.concurrent.atomic.AtomicLong;
5+
import org.jruby.Ruby;
6+
import org.jruby.RubyBoolean;
7+
import org.jruby.RubyClass;
8+
import org.jruby.RubyFixnum;
9+
import org.jruby.RubyModule;
10+
import org.jruby.RubyObject;
11+
import org.jruby.anno.JRubyClass;
12+
import org.jruby.anno.JRubyMethod;
13+
import org.jruby.runtime.ObjectAllocator;
14+
import org.jruby.runtime.ThreadContext;
15+
import org.jruby.runtime.builtin.IRubyObject;
16+
import org.jruby.runtime.load.Library;
17+
18+
public class JavaAtomicFixnumLibrary implements Library {
19+
20+
public void load(Ruby runtime, boolean wrap) throws IOException {
21+
RubyModule concurrentMod = runtime.defineModule("Concurrent");
22+
RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicFixnum", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR);
23+
24+
atomicCls.defineAnnotatedMethods(JavaAtomicFixnum.class);
25+
26+
}
27+
28+
private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() {
29+
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
30+
return new JavaAtomicFixnum(runtime, klazz);
31+
}
32+
};
33+
34+
@JRubyClass(name = "JavaAtomicFixnum", parent = "Object")
35+
public static class JavaAtomicFixnum extends RubyObject {
36+
37+
private AtomicLong atomicLong;
38+
private ThreadContext context;
39+
40+
public JavaAtomicFixnum(Ruby runtime, RubyClass metaClass) {
41+
super(runtime, metaClass);
42+
}
43+
44+
@JRubyMethod
45+
public IRubyObject initialize(ThreadContext context) {
46+
this.atomicLong = new AtomicLong(0);
47+
this.context = context;
48+
return context.nil;
49+
}
50+
51+
@JRubyMethod
52+
public IRubyObject initialize(ThreadContext context, IRubyObject value) {
53+
this.atomicLong = new AtomicLong(rubyFixnumToLong(value));
54+
this.context = context;
55+
return context.nil;
56+
}
57+
58+
@JRubyMethod(name = "value")
59+
public IRubyObject getValue() {
60+
return new RubyFixnum(getRuntime(), atomicLong.get());
61+
}
62+
63+
@JRubyMethod(name = "value=")
64+
public IRubyObject setValue(IRubyObject newValue) {
65+
atomicLong.set(rubyFixnumToLong(newValue));
66+
return context.nil;
67+
}
68+
69+
@JRubyMethod(name = {"increment", "up"})
70+
public IRubyObject increment() {
71+
return new RubyFixnum(getRuntime(), atomicLong.incrementAndGet());
72+
}
73+
74+
@JRubyMethod(name = {"decrement", "down"})
75+
public IRubyObject decrement() {
76+
return new RubyFixnum(getRuntime(), atomicLong.decrementAndGet());
77+
}
78+
79+
@JRubyMethod(name = "compare_and_set")
80+
public IRubyObject compareAndSet(IRubyObject expect, IRubyObject update) {
81+
return RubyBoolean.newBoolean(getRuntime(), atomicLong.compareAndSet(rubyFixnumToLong(expect), rubyFixnumToLong(update)));
82+
}
83+
84+
private long rubyFixnumToLong(IRubyObject value) {
85+
if (value instanceof RubyFixnum) {
86+
RubyFixnum fixNum = (RubyFixnum) value;
87+
return fixNum.getLongValue();
88+
} else {
89+
throw getRuntime().newArgumentError("initial value must be a Fixnum");
90+
}
91+
}
92+
}
93+
}
94+

lib/concurrent/atomic/atomic_boolean.rb

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -115,49 +115,6 @@ def make_false
115115

116116
if RUBY_PLATFORM == 'java'
117117

118-
# @!macro atomic_boolean
119-
class JavaAtomicBoolean
120-
121-
# @!macro atomic_boolean_method_initialize
122-
#
123-
def initialize(initial = false)
124-
@atomic = java.util.concurrent.atomic.AtomicBoolean.new(!!initial)
125-
end
126-
127-
# @!macro atomic_boolean_method_value_get
128-
#
129-
def value
130-
@atomic.get
131-
end
132-
133-
# @!macro atomic_boolean_method_value_set
134-
#
135-
def value=(value)
136-
@atomic.set(!!value)
137-
end
138-
139-
# @!macro atomic_boolean_method_true_question
140-
def true?
141-
@atomic.get
142-
end
143-
144-
# @!macro atomic_boolean_method_false_question
145-
def false?
146-
!@atomic.get
147-
end
148-
149-
# @!macro atomic_boolean_method_make_true
150-
def make_true
151-
@atomic.compareAndSet(false, true)
152-
end
153-
154-
# @!macro atomic_boolean_method_make_false
155-
def make_false
156-
@atomic.compareAndSet(true, false)
157-
end
158-
end
159-
160-
# @!macro atomic_boolean
161118
class AtomicBoolean < JavaAtomicBoolean
162119
end
163120

lib/concurrent/atomic/atomic_fixnum.rb

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,14 @@ def decrement
9797
alias_method :down, :decrement
9898

9999
# @!macro [attach] atomic_fixnum_method_compare_and_set
100-
#
100+
#
101101
# Atomically sets the value to the given updated value if the current
102102
# value == the expected value.
103103
#
104104
# @param [Fixnum] expect the expected value
105105
# @param [Fixnum] update the new value
106106
#
107-
# @return [Boolean] true if the value was updated else false
107+
# @return [Boolean] true if the value was updated else false
108108
def compare_and_set(expect, update)
109109
@mutex.lock
110110
if @value == expect
@@ -120,47 +120,6 @@ def compare_and_set(expect, update)
120120

121121
if RUBY_PLATFORM == 'java'
122122

123-
# @!macro atomic_fixnum
124-
class JavaAtomicFixnum
125-
126-
MIN_VALUE = Java::JavaLang::Long::MIN_VALUE
127-
MAX_VALUE = Java::JavaLang::Long::MAX_VALUE
128-
129-
# @!macro atomic_fixnum_method_initialize
130-
def initialize(init = 0)
131-
raise ArgumentError.new('initial value must be a Fixnum') unless init.is_a?(Fixnum)
132-
@atomic = java.util.concurrent.atomic.AtomicLong.new(init)
133-
end
134-
135-
# @!macro atomic_fixnum_method_value_get
136-
def value
137-
@atomic.get
138-
end
139-
140-
# @!macro atomic_fixnum_method_value_set
141-
def value=(value)
142-
raise ArgumentError.new('value must be a Fixnum') unless value.is_a?(Fixnum)
143-
@atomic.set(value)
144-
end
145-
146-
# @!macro atomic_fixnum_method_increment
147-
def increment
148-
@atomic.increment_and_get
149-
end
150-
alias_method :up, :increment
151-
152-
# @!macro atomic_fixnum_method_decrement
153-
def decrement
154-
@atomic.decrement_and_get
155-
end
156-
alias_method :down, :decrement
157-
158-
# @!macro atomic_fixnum_method_compare_and_set
159-
def compare_and_set(expect, update)
160-
@atomic.compare_and_set(expect, update)
161-
end
162-
end
163-
164123
# @!macro atomic_fixnum
165124
class AtomicFixnum < JavaAtomicFixnum
166125
end

0 commit comments

Comments
 (0)